Doing Things in Parallel: Promise.all

Freshman Year, page 6 of 10. A one-minute read.

Using await one after another runs tasks in sequence: each one waits for the previous one to finish. That's what you want when each step needs the previous result. But if the tasks are independent, waiting for each in turn is a waste of time.

Imagine making breakfast. You could boil the kettle, wait for it, then make toast, wait for it, then fry an egg. Or you could start all three at once and be done in a third of the time.

Promise.all takes an array of promises, runs them all at the same time, and gives you back a promise for an array of all their results:

JavaScript
function wait(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function makeItem(name, ms) {
  await wait(ms);
  return name;
}

async function breakfast() {
  const start = Date.now();

  const [tea, toast, egg] = await Promise.all([
    makeItem("☕ tea", 300),
    makeItem("🍞 toast", 200),
    makeItem("🍳 egg", 300),
  ]);

  const seconds = Math.round((Date.now() - start) / 100) / 10;
  console.log(`Breakfast is ready: ${tea}, ${toast}, ${egg}`);
  console.log(`Total time: about ${seconds} seconds`);
}

breakfast();

It prints

Breakfast is ready: ☕ tea, 🍞 toast, 🍳 egg
Total time: about 0.3 seconds

All three items were "cooked" at the same time, so the whole breakfast took 0.3 seconds (the time of the slowest item), not 0.8 seconds (all three added up).

If any of the promises rejects, Promise.all rejects immediately. If you'd rather wait for all of them and see which ones worked and which ones failed, use Promise.allSettled instead.

Reading is step one

CurlyScript turns these notes into a game: short questions, an explanation after every answer, and a test at the end of each grade. Free, with nothing to sign up for.

Start learning