Reputation: 75
I have this code snippet that should await
5 promises, pause for 2 seconds and then continue to await
another 5. However, the output shows that the two Promise.all
are not awaited although when I tried to return a value in the promise it returns properly. Am I understanding the concept of Promise.all
wrong or there is something missing in my code?
(function () {
let val = 0
const promiseArr = []
for (let i = 0; i < 10; i++) {
promiseArr[i] = new Promise((res) => {
val += 500
setTimeout((val2) => {
console.log(val2)
res()
}, val, val)
})
}
console.log();
(async function() {
await Promise.all(promiseArr.slice(0, 5))
console.log('start await')
await new Promise((res) => setTimeout(res, 2000))
console.log('done await')
await Promise.all(promiseArr.slice(6, 10))
})()
}) ()
Expected output:
500
...
2500
start await
done await
3000
...
5000
Actual output:
500
1000
1500
2000
2500
start await
3000
3500
4000
4500
done await
5000
EDIT: Now I understand why it behaves like that. Looks like I misunderstood a fundamental concept with Promises. Thanks for you guys help!
Upvotes: 1
Views: 208
Reputation: 399
I stumbled on this misunderstanding myself too: when you define a Promise, it's function is executed in that moment. If I understand what you're trying to do, you need to define an array of functions, and call them as needed.
(function () {
let val = 0
const promiseArr = []
for (let i = 0; i < 10; i++) {
promiseArr[i] = () => new Promise((res) => {
val += 500
setTimeout((val2) => {
console.log(val2)
res()
}, val, val)
})
}
console.log();
(async function() {
await Promise.all(promiseArr.slice(0, 5).map((fn) => fn()))
console.log('start await')
await new Promise((res) => setTimeout(res, 2000))
console.log('done await')
await Promise.all(promiseArr.slice(6, 10).map((fn) => fn()))
})()
}) ()
Upvotes: 0
Reputation: 169378
You're seeing this because the promises begin running as soon as they are created (or, well, as soon as the current synchronous block finishes anyway), not when they are await
ed upon.
Instrumenting and reorganizing your code a little, to print timestamps for each event might illuminate things:
const t0 = +new Date();
const logWithTime = (message = "") =>
console.log("" + Math.round(+new Date() - t0) + ": " + message);
(async function() {
let val = 0;
const resolver = res => {
val += 500;
const thisVal = val; // so we have a binding for the effective value
logWithTime("Creating timeout for " + thisVal);
setTimeout(
arg => {
logWithTime("Timeout for " + thisVal);
res();
},
thisVal,
thisVal,
);
};
const promiseArr = [];
for (let i = 0; i < 10; i++) {
promiseArr[i] = new Promise(resolver);
}
logWithTime("awaiting for first 5...");
await Promise.all(promiseArr.slice(0, 5));
logWithTime("waiting for 2 seconds...");
await new Promise(res => setTimeout(res, 2000));
logWithTime("waiting for the rest...");
await Promise.all(promiseArr.slice(6, 10));
logWithTime("all done");
})();
prints
0: Creating timeout for 500
10: Creating timeout for 1000
10: Creating timeout for 1500
10: Creating timeout for 2000
10: Creating timeout for 2500
10: Creating timeout for 3000
10: Creating timeout for 3500
10: Creating timeout for 4000
10: Creating timeout for 4500
10: Creating timeout for 5000
10: awaiting for first 5...
511: Timeout for 500
1011: Timeout for 1000
1515: Timeout for 1500
2013: Timeout for 2000
2510: Timeout for 2500
2511: waiting for 2 seconds...
3010: Timeout for 3000
3512: Timeout for 3500
4011: Timeout for 4000
4511: Timeout for 4500
4511: waiting for the rest...
5011: Timeout for 5000
5011: all done
(or thereabouts, depending on things).
You can see the order in which the timeouts get resolved there.
Upvotes: 2
Reputation: 944320
Your timers start ticking when you call setTimeout
, not when you await
the promise that is resolved by them.
While (res) => setTimeout(res, 2000)
runs, you have 4 prior setTimeouts
which finish and call console.log
before resolving.
Upvotes: 1