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
6 Answers
Reset to default 6You 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!!!