Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to run several async operations in parallel

Short answer

Promise.all() starts waiting for all promises at once and returns an array of results in the same order:

const delay = (ms, value) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
 
const start = Date.now();
const [user, orders] = await Promise.all([delay(300, 'Anna'), delay(300, 3)]);
 
console.log(user, orders);
console.log(Date.now() - start < 500 ? 'about 300 ms, not 600' : 'slow');

Output:

Anna 3
about 300 ms, not 600

With fetch

The same with requests: both start at once:

const [user, orders] = await Promise.all([
  fetch('/api/user').then((r) => r.json()),
  fetch('/api/orders').then((r) => r.json()),
]);

When some may fail

Promise.all() fails as soon as one promise fails. Promise.allSettled() waits for all and reports the status of each:

const results = await Promise.allSettled([
  Promise.resolve('photo 1'),
  Promise.reject(new Error('photo 2 is too large')),
  Promise.resolve('photo 3'),
]);
 
for (const result of results) {
  console.log(result.status, result.value ?? result.reason.message);
}

Output:

fulfilled photo 1
rejected photo 2 is too large
fulfilled photo 3

Common mistake

await in a loop runs the operations one by one. If they do not depend on each other, that is just slower:

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const start = Date.now();
 
for (const ms of [200, 200, 200]) {
  await delay(ms);
}
 
console.log(Date.now() - start >= 600 ? 'one by one: 600 ms' : 'fast');

Output:

one by one: 600 ms

Functions used in this recipe

  • Promise.all — Waits for all promises in parallel.
  • Promise.allSettled — Waits for every promise to settle and reports each result — success or failure.

Thanks for reading!

Donate to the site — we work hard for you.