Sequential vs parallel
| For-await in order | |
| Parallel with map+all | |
| Limit concurrency simply | |
| Choose by dependency |
For-await in order
A plain for loop with await runs tasks in strict order. Each iteration waits for the prior one to settle. This is the safest shape when order matters or the server allows only one call at a time.
async function fetchOne(id: number): Promise<string> {
return "user " + id;
}
async function inOrder(ids: number[]): Promise<void> {
for (const id of ids) {
const u = await fetchOne(id);
console.log(u);
}
}
Parallel with map+all
Map plus all starts every task without waiting between launches. The total wait is close to the slowest single task. Use this shape for independent calls that can safely overlap.
async function allAtOnce(ids: number[]): Promise<void> {
const users: string[] = await Promise.all(ids.map(fetchOne));
console.log(users.length);
}
Limit concurrency simply
Full parallel can flood a server, so process inputs in small batches. Slice the list into chunks and await all for one chunk at a time. Batch size two or five covers most cases without extra libraries.
async function batched(ids: number[]): Promise<void> {
const size = 2;
for (let i = 0; i < ids.length; i += size) {
const chunk = ids.slice(i, i + size);
await Promise.all(chunk.map(fetchOne));
}
}
Choose by dependency
Choose serial when one step needs the value from the prior step. Choose parallel when inputs are ready up front and do not interact. When in doubt, start serial for clarity and switch to batches once timing proves the need.
async function choose(ids: number[], parallel: boolean): Promise<void> {
if (parallel) {
await allAtOnce(ids);
} else {
await inOrder(ids);
}
}
Next: Event loop
Article author: Arthur Isaev