Is there any difference between this:
const promises = await Promise.all(items.map(e => somethingAsync(e)));
for (c
Actually, using the for await
syntax does fire the promises all at once.
The small piece of code proves it:
const sleep = s => {
return new Promise(resolve => {
setTimeout(resolve, s * 1000);
});
}
const somethingAsync = async t => {
await sleep(t);
return t;
}
(async () => {
const items = [1, 2, 3, 4];
const now = Date.now();
for await (const res of items.map(e => somethingAsync(e))) {
console.log(res);
}
console.log("time: ", (Date.now() - now) / 1000);
})();
stdout:
time: 4.001
But the inside of the loop doesn't act "as a callback". If I reverse the array, all the logs appear at once. I suppose that the promises are fired at once and the runtime just waits for the first one to resolve to go to the next iteration.
EDIT: Actually, using for await
is bad practice when we use it with something other than an asynchronous iterator, best is to use Promise.all
, according to @Bergi in his answer.
Yes, they absolutely are different. for await
is supposed to be used with asynchronous iterators, not with arrays of pre-existing promises.
Just to make clear,
for await (const res of items.map(e => somethingAsync(e))) …
works the same as
const promises = items.map(e => somethingAsync(e));
for await (const res of promises) …
or
const promises = [somethingAsync(items[0]), somethingAsync(items[1]), …);
for await (const res of promises) …
The somethingAsync
calls are happening immediately, all at once, before anything is awaited. Then, they are await
ed one after another, which is definitely a problem if any one of them gets rejected: it will cause an unhandled promise rejection error. Using Promise.all
is the only viable choice to deal with the array of promises:
for (const res of await Promise.all(promises)) …
See Waiting for more than one concurrent await operation and Any difference between await Promise.all() and multiple await? for details.
As you said Promise.all
will send all the requests in one go and then you will get the response when all of them gets completed.
In the second scenario, you will send the request in one go but recieve response as for each one by one.
See this small example for reference.
let i = 1;
function somethingAsync(time) {
console.log("fired");
return delay(time).then(() => Promise.resolve(i++));
}
const items = [1000, 2000, 3000, 4000];
function delay(time) {
return new Promise((resolve) => {
setTimeout(resolve, time)
});
}
(async() => {
console.time("first way");
const promises = await Promise.all(items.map(e => somethingAsync(e)));
for (const res of promises) {
console.log(res);
}
console.timeEnd("first way");
i=1; //reset counter
console.time("second way");
for await (const res of items.map(e => somethingAsync(e))) {
// do some calculations
console.log(res);
}
console.timeEnd("second way");
})();
You could try it here as well - https://repl.it/repls/SuddenUselessAnalyst
Hope this helps.