CodeBlanks Logo Icon CodeBlanks

Summary - Async patterns

JavaScript course · Advanced · Lesson 77/100

Safely manage multiple API calls with Promise.allSettled and for await...of.

Summary - Async patterns

You learned five important async patterns. Promise.allSettled collects every result without losing any; Promise.any picks the first success; Promise.race takes the first to settle (ideal for timeouts). Async iterables walk paginated data like a stream; the pool pattern limits concurrency.

Which one to pick depends on the scenario: all for 'all or nothing', allSettled for 'best effort', any for 'first success', race for 'first to settle', async iterables for 'streaming', pool for 'rate limit'.

Exercise Safe multiple calls

Write an async function called fetchAll(urls). Await Promise.allSettled over urls.map(u => fetch(u)). Filter the results: keep those with status === 'fulfilled' in ok, and those with status === 'rejected' in bad. Log 'ok' and ok.length, then 'bad' and bad.length with console.log. Test with fetchAll(['/users', '/posts', '/comments']).

Show example solution
async function fetchAll(urls) {
  const results = await Promise.allSettled(urls.map(u => fetch(u)));
  const ok = results.filter(r => r.status === 'fulfilled');
  const bad = results.filter(r => r.status === 'rejected');
  console.log('ok', ok.length);
  console.log('bad', bad.length);
}
fetchAll(['/users', '/posts', '/comments']);

A guide to choosing a pattern

Ask these questions when deciding: 'Must all succeed?' → Promise.all. 'Can some results be lost?' → Promise.allSettled. 'Is only the first success enough?' → Promise.any. 'Is the first to settle (success or fail) what matters?' → Promise.race. 'Does data arrive over time?' → async iterable. 'Are there too many jobs at once?' → pool pattern.

These questions help you pick the right pattern quickly; the code becomes safer and more readable.

Exercise Rate-limited batch calls

Write an async function called fetchBatched(urls, limit). Create an empty array named all. Use a for loop to split urls into groups of size limit (with slice). Call Promise.allSettled for each group (via batch.map(u => fetch(u))); push the results with all.push(...out). Finally, return all. Test with fetchBatched(['/a', '/b', '/c', '/d', '/e'], 2) and log the length of the returned array with console.log.

Show example solution
async function fetchBatched(urls, limit) {
  const all = [];
  for (let i = 0; i < urls.length; i = i + limit) {
    const batch = urls.slice(i, i + limit);
    const out = await Promise.allSettled(batch.map(u => fetch(u)));
    all.push(...out);
  }
  return all;
}
fetchBatched(['/a', '/b', '/c', '/d', '/e'], 2).then(r => console.log(r.length));

Test yourself

  1. One of five API calls will definitely reject. You want to see every result. Which pattern is safest?

    • Promise.all — it is fast
    • Promise.race — it takes the first result
    • Promise.allSettled — it captures rejections too
    • Promise.any — it wants only successes
    Show answer

    Promise.allSettled — it captures rejections too — Correct! allSettled does not lose other results because of one rejection.

  2. Match patterns to their use cases

    allSettled
    partial batch
    any
    redundant endpoints
    race
    timeout
    pool
    rate limit
    for await...of
    streaming

All lessons in Advanced