Promise.All function invocation issue - javascript

I'm using Promise.all function to resolve the multiple promises concurrently. See the below code -
function check1() {
console.log('check 1 invoked')
return new Promise((resolve, reject) => {
setTimeout(()=> resolve('check1'), 4000);
})
}
function check2() {
console.log('check2 invoked')
return new Promise((resolve, reject) => {
setTimeout(()=> resolve('check2'), 4000);
})
}
var arr = [check1(), check2()];
Promise.all(arr)
.then((response) => console.log('response======>',response))
.catch((error) => console.error('error',error))
The problem with the above approach is that when I create the promise array, The respective functions gets invoked. I want to change the above code in the manner that two functions call only from the promise.all function.
Note - Need to store the promises functions in the array. Like I'm doing as var arr.

This should do it, do not make an array of promises but an array of functions, then map the functions to promises:
function check1() {
console.log('check 1 invoked')
return new Promise((resolve, reject) => {
setTimeout(()=> resolve('check1'), 4000);
})
}
function check2() {
console.log('check2 invoked')
return new Promise((resolve, reject) => {
setTimeout(()=> resolve('check2'), 4000);
})
}
//do not store the promises, store the funciton that creates a promise
var arr = [check1, check2];
Promise.all(
//map functions to promises
arr.map(fn=>fn())
)
.then((response) => console.log('response======>',response))
.catch((error) => console.error('error',error))

You can do in this way too -
var check1 = new Promise((resolve, reject) => {
setTimeout(()=> resolve('check1'), 4000);
});
var check2 = new Promise((resolve, reject) => {
setTimeout(()=> resolve('check2'), 4000);
});
Promise.all([check1, check2]).then(values => {
console.log(values);
}, reason => {
console.log(reason)
});

Related

Promise.all.then is executed before the individual promises are completed

The following sample code represents what am trying to do, and am stumped as to why the console.log inside the Promises.all.then() is completed before even the individual promises are completed. I am thinking that the map statement has something to do with it , may be, but am unsure.
My intention of using a map was to collect all successes and or failures and notify the user later on bulk operations.
var requests = []; var success=[]; var failures = [];
requests.push(new Promise((resolve, reject) => setTimeout(() => resolve("foo success"), 2000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => reject("bar failure"), 1000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => resolve("foo2 success"), 2000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => reject("bar2 failure"), 1000)));
Promise.all(requests.map(p => {
p.then(r => {
console.log(r)
success.push(r);
});
p.catch((e) => { console.log(e); failures.push(e); });
})).then(function () { console.log("ALL promises completed")})
May i know what is wrong with the above code? Am i not implementing the promises as intended.?
It's because your requests.map(...) callback doesn't return anything, so you're mapping the Promises to undefined values. Therefore, you're awaiting an array of undefined values with the Promise.all call. Change to the following:
Promise.all(requests.map(p => {
p.then(r => {
console.log(r)
console.log("POSTed a record successfuly");
success.push(r);
});
p.catch((e) => { console.log(e); failures.push(e); });
return p;
})).then(function () { console.log("POSTED ALL")})
Update:
As #JoeFrambach pointed out, if you want the Promise.all to contain the contents of the original requests Promises, you'll want to return the original Promises. Since that's most likely what you want to do, I've updated my answer.
just return promise from your map callback function
var requests = []; var success=[]; var failures = [];
requests.push(new Promise((resolve, reject) => setTimeout(() => resolve("foo success"), 2000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => reject("bar failure"), 1000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => resolve("foo2 success"), 2000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => reject("bar2 failure"), 1000)));
Promise.all(requests.map(p => {
p.then(r => {
console.log(r)
success.push(r);
});
p.catch((e) => { console.log(e); failures.push(e); });
return p; // ADD THIS LINE
})).then(function () { console.log("ALL promises completed")})
.catch(function() {console.log("FAILED PROMISE ALL")});
You need to return a promise within .map function.
Within .map function make last line as return p.
Promise all expects array of promises. You are returning array of undefined from map function so it immediately gets resolved.

About Node.js Promise then and return?

I'm confused about Promise!
I use Promise then without return like this:
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1");
new Promise((resolve, reject) => {
//Time-consuming operation, for example: get data from database;
setTimeout(() => {
resolve(2)
}, 3000);
}).then((v11) => {
console.log("v11");
})
}).then((v2) => {
console.log("v2")
});
I get this result v1 v2 v11.
Then, I use another way of writing, Like below:
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1");
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 3000)
}).then((v11) => {
console.log("v11");
})
}).then((v2) => {
console.log("v2")
});
I get another result v1 v11 v2.
Maybe, There is another case:
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1");
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 3000)
}).then((v11) => {
console.log("v11");
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 4000)
}).then(() => {
console.log("v12")
})
})
}).then((v2) => {
console.log("v2")
});
I get this result v1 v11 v12 v2
I can't understand the second return I want to know why I get this result?
It will be easier to understand the control flow if you actually print the values of the resolved promises and not only the names of the variables:
Version 1
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1:", v1);
new Promise((resolve, reject) => {
//Time-consuming operation, for example: get data from database;
setTimeout(() => {
resolve(2)
}, 3000);
}).then((v11) => {
console.log("v11:", v11);
})
}).then((v2) => {
console.log("v2:", v2)
});
Version 2
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1:", v1);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 3000)
}).then((v11) => {
console.log("v11:", v11);
})
}).then((v2) => {
console.log("v2:", v2)
});
Version 3
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1:", v1);
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 3000)
}).then((v11) => {
console.log("v11:", v11);
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 4000)
}).then((v12) => {
console.log("v12:", v12)
})
})
}).then((v2) => {
console.log("v2:", v2)
});
Now you can see what gets passed to the callbacks:
Result 1
v1: 1
v2: undefined
v11: 2
Result 2
v1: 1
v11: 2
v2: undefined
Result 3
v1: 1
v11: 2
v12: 2
v2: undefined
Explanation
As you can see when in the .then() handlers you don't return a promise, it acts as if you returned an already resolved promise with value undefined - like if you did:
return Promise.resolve(undefined);
and thus the next .then() handler can be called immediately.
If, on the other hand, you return a promise that is not resolved yet, then the next .then() handler will not be invoked immediately but only after that returned promise gets resolved.
And that explains the order of execution that is different when you don't return a promise - and what happens is as if an already resolved promise got returned implicitly for you.
function one() {
return new Promise((resolve,reject) => {
setTimeout(function () {
console.log("one 1 ");
resolve('one one');
}, 2000);
});
}
function two() {
return new Promise((resolve,reject) => {
setTimeout(function () {
console.log("two 2 ");
resolve('two two');
}, 10000);
});
}
function three(){
setTimeout(function () {
console.log("three 3 ");
}, 5000);
}
one().then((msg) => {
console.log('one : ', msg);
return two();
}).then((msg) => {
console.log('two :', msg);
return three();
}).then((msg) => {
console.log('three :', msg);
})
.catch((error) => {
console.error('Something bad happened:', error.toString());
});
console three show undefined because three not parse resolve

Async function inside Promises

Here is my situation:
fetchData(foo).then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(result + bar);
}, 0)
});
}).then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve( result + woo);
}, 0)
});
}).then(result => {
setTimeout(() => {
doSomething(result);
}, 0)
});
Where each setTimeout is a different async operation using the callback pattern.
It is really painfull to wrap each function inside a promise, I feel like the code should look more like this:
fetchData(foo).then(result => {
setTimeout(() => {
return result + bar;
}, 0)
}).then(result => {
setTimeout(() => {
return result + woo;
}, 0)
}).then(result => {
setTimeout(() => {
doSomething(result);
}, 0)
});
Obviously this doesn't work.
Am I using Promises right? Do I really have to wrap all existing async function in promises?
EDIT:
Actually I realize my example was not totally reprensentative of my situation, I did not make it clear that the setTimeout in my example is meant to reprensent en async operation. This situation is more representative of my situation:
fetchData(foo).then(result => {
return new Promise((resolve, reject) => {
asyncOperation(result, operationResult => {
resolve(operationResult);
}, 0)
});
}).then(result => {
return new Promise((resolve, reject) => {
otherAsyncOperation(result, otherAsyncResult => {
resolve( otherAsyncResult);
}, 0)
});
}).then(result => {
doSomething(result);
});
Am I using Promises right? Do I really have to wrap all existing async function in promises?
Yes. Yes.
I feel like the code should look more like this
No, it shouldn't. It rather should look like this:
function promiseOperation(result) {
return new Promise((resolve, reject) => {
asyncOperation(result, resolve, 0)
});
}
function otherPromiseOperation(result) {
return new Promise((resolve, reject) => {
otherAsyncOperation(result, resolve, 0)
});
}
fetchData(foo).then(promiseOperation).then(otherPromiseOperation).then(doSomething);
It is really painfull to wrap each function inside a promise
Well, don't repeatedly write it out every time. You can abstract this wrapping into a function!
function promisify(fn) {
return value => new Promise(resolve => {
fn(value, resolve, 0)
});
}
const promiseOperation = promisify(asyncOperation);
const otherPromiseOperation = promisify(otherAsyncOperation);
fetchData(foo).then(promiseOperation).then(otherPromiseOperation).then(doSomething);
Notice that most promise libraries come with a such a promisification function included, so your whole code reduces to these three lines.
You are using promise right. Just a small note on the first snippet of code: you are not returning a promise from the last then() callback:
...
}).then(result => {
setTimeout(() => {
doSomething(result);
}, 0)
});
This is correct if you need simply to do an async operation without returning to the caller of fetchData the value of the last async operation. If you need to return this value, you need to convert to promise this operation too:
fetchData(foo).then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(result + bar);
}, 0)
});
}).then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(result + woo);
}, 0)
});
}).then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(doSomething(result));
}, 0)
});
});
Here I suppose doSomething is a sync function returning a value.
Said so, if you want to reduce the noise of create the promise to wrap setTimeout every time, you can create a utility function setTimeoutWithPromise:
function setTimeoutWithPromise(operation, millisec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(operation());
}, millisec)
});
}
And clean your code:
fetchData(foo)
.then(result => setTimeoutWithPromise(() => result + bar, 0))
.then(result => setTimeoutWithPromise(() => result + woo, 0))
.then(result => setTimeoutWithPromise(() => doSomething(result), 0));

How to execute functions sequentially using Node Js Promise?

I'm new to Node js Promise I'm not sure whether I'm using the Promise correctly or not so here is my code.
function print(){
first('first')
.then(second('second'))
.then(third('third'));
}
function first(a){
return new Promise((resolve, reject) => {
var res1 = function (){
resolve(a);
}
});
console.log(a);
}
function second(b){
return new Promise((resolve, reject) => {
var res1 = function (){
resolve(b);
}
});
setTimeout(() => {
console.log(b);
}, 2000);
}
function third(c){
return new Promise((resolve, reject) => {
var res1 = function (){
resolve(c);
}
});
console.log(c);
}
My desired output is
first
second
third
Instead what I get is
first
third
//after two seconds
second
I'm missing something but I can't figure it out please explain me
To get the expected behaviour, you need to resolve inside of the timeout (next to the console log). You also cannot pass arguments into promise chain functions since they need to accept the promise from the previous thennable.
A working snippet is below:
print();
function print(){
first('first')
.then(second)
.then(third);
}
function first(a){
return new Promise((resolve, reject) => {
console.log(a);
resolve(a);
});
}
function second(b){
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("second");
resolve(b);
}, 2000);
});
}
function third(c){
return new Promise((resolve, reject) => {
console.log("third");
resolve(c)
});
}

How to structure nested Promises

I have a situation where I think the only choice for me is to nest some Promises within each other. I have a Promise that needs to be performed and a method that does something until that Promise is complete. Something like this:
let promise = new Promise((resolve, reject) => {
// Do some stuff
});
doSomethingUntilPromiseisDone(promise);
However, within my Promise, I need to execute another method that returns another Promise:
let promise = new Promise((resolve, reject) => {
fetchValue(url)
.then((value) => {
// Do something here
}).catch((err) => {
console.error(err);
});
});
doSomethingUntilPromiseisDone(promise);
But now, in the fetchValue method's then statement, I have another method I need to execute that, guess what, returns another Promise:
let promise = new Promise((resolve, reject) => {
fetchValue(url)
.then((value) => {
saveToCache(value)
.then((success) => {
console.log('success!!');
resolve('success');
});
}).catch((err) => {
console.error(err);
});
});
doSomethingUntilPromiseisDone(promise);
So in the end, I have a Promise, within a Promise, within a Promise. Is there someway I can structure this better so that it is more straightforward? It seems like nesting them within each other is counter to Promise's intended chaining approach.
Use .then()
let doStuff = (resolve, reject) => {/* resolve() or reject() */};
let promise = new Promise(doStuff);
doSomethingUntilPromiseisDone(
promise
.then(value => fetchValue(url))
.then(value => value.blob())
.then(saveToCache)
)
.then(success => console.log("success!!"))
.catch(err => console.error(err))
you can use generator to flatten your nested promises (Bluebird.couroutine or Generators)
//Bluebird.couroutine
const generator = Promise.coroutine(function*() {
try {
const value = yield fetchValue(url);
const success = yield saveToCache(value);
console.log('success:', success);
} catch(e) {
console.error(err);
}
}));
generator();
Each function will call the next one with the result of the method before.
var promises = [1,2,3].map((guid)=>{
return (param)=> {
console.log("param", param);
var id = guid;
return new Promise(resolve => {
// resolve in a random amount of time
setTimeout(function () {
resolve(id);
}, (Math.random() * 1.5 | 0) * 1000);
});
}
}).reduce(function (acc, curr, index) {
return acc.then(function (res) {
return curr(res[index-1]).then(function (result) {
console.log("result", result);
res.push(result);
return res;
});
});
}, Promise.resolve([]));
promises.then(console.log);

Categories