Should you use await inside a for loop or Promise.all for independent tasks?
For independent tasks use Promise.all with map so they run concurrently. await inside a loop runs them one by one, which is right only when each step depends on the last or order and rate limits matter.
Explain it simply
You have to pay five electricity bills online. If you pay one, wait for the receipt, then start the next, it takes five times as long. If you open five tabs and pay them together, it takes about as long as the slowest one. A loop with await is the first approach; Promise.all is the second.
Example
const ids = [1, 2, 3, 4, 5];
// sequential: about 5 x 200 ms = 1000 ms
async function sequential() {
const out = [];
for (const id of ids) {
out.push(await fetchStudent(id));
}
return out;
}
// concurrent: about 200 ms
async function concurrent() {
return Promise.all(ids.map((id) => fetchStudent(id)));
}Use the loop when:
- Each call needs the previous result.
- Order of side effects matters, such as numbered invoices.
- You must respect a rate limit or avoid overloading a database.
For thousands of items, even Promise.all is risky, since it starts everything at once. Process in batches of, say, 10 to 50 at a time, or use a limiter library such as p-limit.
Also, array.forEach(async ...) does not wait for anything. Use for...of or Promise.all(map).
What to say in the interview
"Independent work should run concurrently with Promise.all; dependent or rate-limited work goes in a for...of loop with await. For large lists I batch the calls to avoid overload."
Common mistakes
- Using
forEachwith async callbacks and expecting it to finish before the next line. - Firing ten thousand promises at once.