最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Launch a promise every X seconds - Stack Overflow

programmeradmin1浏览0评论

I'm pulling data from 3 differents APIs, and I want to merge all these results into one array.

I guess the proper way to do this is to use Promises:

var function1 = new Promise((resolve, reject)=>{
    ...
    resolve();
});
var function2 = new Promise((resolve, reject)=>{
    ...
    resolve();
});
var function3 = new Promise((resolve, reject)=>{
    ...
    resolve();
});

Promise.all([function1, function2, function3]).then(function(values){
    // Values are all here!
});

How can I call all the promises again and join them via Promise.all every second?

I've tried

setInterval(function(){
    Promise.all([function1, function2, function3]).then(function(values){
        // Values are all here and up to date!
    });
}, 1000)

without success.

Thanks for your help!

I'm pulling data from 3 differents APIs, and I want to merge all these results into one array.

I guess the proper way to do this is to use Promises:

var function1 = new Promise((resolve, reject)=>{
    ...
    resolve();
});
var function2 = new Promise((resolve, reject)=>{
    ...
    resolve();
});
var function3 = new Promise((resolve, reject)=>{
    ...
    resolve();
});

Promise.all([function1, function2, function3]).then(function(values){
    // Values are all here!
});

How can I call all the promises again and join them via Promise.all every second?

I've tried

setInterval(function(){
    Promise.all([function1, function2, function3]).then(function(values){
        // Values are all here and up to date!
    });
}, 1000)

without success.

Thanks for your help!

Share Improve this question asked Jan 31, 2018 at 16:10 VicoVico 1,2561 gold badge25 silver badges60 bronze badges 4
  • You can push it in a single array with a global variable – praveenkumar s Commented Jan 31, 2018 at 16:16
  • Possible duplicate of Resolve a chain of promises with timeouts. Promise.all – ponury-kostek Commented Jan 31, 2018 at 16:40
  • 1 First off... don't do this in a setInterval... not unless you want to increase the delay to 10seconds or more. Otherwise you're just gonna end up with a backlog of requests pending. – Kevin B Commented Jan 31, 2018 at 16:45
  • You are right thank you @KevinB – Vico Commented Jan 31, 2018 at 17:19
Add a ment  | 

6 Answers 6

Reset to default 6

You need to recreate the Promise objects every time you want to invoke them:

var function1 = (resolve, reject)=>{
    console.log('calling 1');
    resolve();
};
var function2 = (resolve, reject)=>{
    console.log('calling 2');
    resolve();
};
var function3 = (resolve, reject)=>{
    console.log('calling 3');
    resolve();
};

setInterval(function(){
    Promise.all([new Promise(function1), new Promise(function2), new Promise(function3)]).then(function(values){
        console.log('alldone');
    });
}, 1000)

This is because the promise is only executed upon creation, and otherwise in your loop you're just attaching a new then() method which will not call your API.

EDIT: Be advised that setInterval, as shown, will fire three requests to your API every 1 second. That's a pretty fast rate of fire and is likely to get you in trouble unless both your API and the network are blazing fast. A more sensible approach might be to only fire the next request once the previous one has been handled. To do that, simply substitute the setInterval call with this:

var callback = function(){
    Promise.all([new Promise(function1), new Promise(function2), new Promise(function3)]).then(function(values){
        console.log('all done');
        setTimeout(callback, 1000);
        console.log('next call successfully enqued');
    });
};
setTimeout(callback, 1000);

Thanks to Kevin B for pointing this out.

Make sure you call the API each time (by creating new Promise).

/**
 * Create function that return a NEW Promise each time.
 * Once resolved a promise won't change state
 */
const function1 = () => new Promise((resolve, reject)=>{
    // something
    resolve('1 - ' + new Date());
});
const function2 = () => new Promise((resolve, reject)=>{
    // something
    resolve('2 - ' + new Date());
});
const function3 = () => new Promise((resolve, reject)=>{
    // something
    resolve('3 - ' + new Date());
});

/**
 * For the setInterval callback, create a function 
 * that will return a new Promise from all the previous promises
 */
const all = () => Promise.all([
    function1(),
    function2(),
    function3()
]).then(function(values){
    console.log(values);
    return values;
});

setInterval(all, 1000);

Answer

This question was in my interview and I had trouble that it should be implemented only using class, maybe you will find it useful for you and rewrite it using functions.

class HTTPService {
    constructor(base = "", strategy = "default" | "queue", promises = []) {
      this.base = base;
      this.strategy = strategy;
      this.promises = 0;
    }
    urlSerializer(payload) {
      return `?${Object.entries(payload)
             .map((el) => el.join("="))
             .join("$")}`;
    }
    returnDefaultPromise(path) {
      return new Promise((resolve) =>
          setTimeout(() => {
              resolve(path);
          }, 1000)
      );
    }
    returnQueuePromise(path) {
      return new Promise((resolve) =>
        setTimeout(() => {
          this.promises -= 1000;
          resolve(path);
        }, this.promises)
      );
    }
    get(url, payload) {
      let serialized = payload ? this.urlSerializer(payload) : "";
      if (!url) throw new Error("Please add url to function argument");
      switch (this.strategy) {
        case "default":
          return this.returnDefaultPromise(`${this.base}/${url}${serialized}`);
        case "queue":
          this.promises += 1000;
          return this.returnQueuePromise(`${this.base}/${url}${serialized}`);
        default:
          return new Promise((resolve) =>
              resolve(`${this.base}/${url}${serialized}`)
            );
        }
    }
}

const httpService = new HTTPService("http://test.", "queue");
const httpService2 = new HTTPService("http://test.", "default");
const br = document.createElement('br');
let div = document.createElement('div');
let content = document.createTextNode('');
httpService.get("/api/me").then((data) => {
  content = document.createTextNode(data);
  div.appendChild(content);
  div.appendChild(br);
  console.log(data);
});
// should be 'http://test./api/me'
// B:
httpService.get("/api/test", { foo: 1, test: 2 }).then((data) => {
  content = document.createTextNode(data);
  div.appendChild(content);
  div.appendChild(br);
  console.log(data);
  // should be 'http://test./api/test?foo=1&test=2'
});
// C:
httpService.get("/api/test", { baz: 10, case: "some" }).then((data) => {
  content = document.createTextNode(data);
  div.appendChild(content);
  div.appendChild(br);
  console.log(data);
  // should be 'http://test.//api/test?baz=10$case=some'
});
// D:
httpService.get("/api/test", { bar: 1, dummy: "text" }).then((data) => {
  content = document.createTextNode(data);
  div.appendChild(content);
  div.appendChild(br);
  console.log(data);
  // should be 'http://test.//api/test?bar=1$dummy=text'
});
httpService2.get("/app/test").then((data) => {
  content = document.createTextNode(data);
  div.appendChild(br);
  div.appendChild(content);
  div.appendChild(br);
  console.log(data);
});
document.querySelector('#result').appendChild(div)
<div id="result"></div>

This example to call functions

Also you can check analogy in react application through codesandbox

An alternative to setInterval() is using setTimeout() inside a recursive loop:

function joinedResults() {
    Promise.all([function1, function2, function3])
        .then(function(values){
            console.log(values);
            setTimeout(()=>{ joinedResults() }, 1000);
        });
}

joinedResults();

This stackoverflow post has a similar question.

In order to chain your promise outside of setInterval, you can wrap it in a function:

let repeat = (ms, func) => new Promise(r => (setInterval(func, ms), wait(ms).then(r)));

repeat(1000, () => Promise.all([myfunction()])
      .then(...)

Solution

Every time you need to create promises again and resolve them.

setInterval(function(){
    var function1 = new Promise((resolve, reject)=>{
        resolve(new Date());
    });
    var function2 = new Promise((resolve, reject)=>{
        resolve(2);
    });
    var function3 = new Promise((resolve, reject)=>{
        resolve(3);
    });
    Promise.all([function1, function2, function3]).then(function(values){
        console.log(values);
    });
}, 1000)

Run the above code its working!!!

发布评论

评论列表(0)

  1. 暂无评论