Async JavaScript Cheat Sheet

Understand the event loop, promises, and async/await, then fetch data and cancel work with confidence. Mental models for async code you can trust, whether you or an AI wrote it. You can also download the information as a printable cheat sheet:

Free Bonus: Async JavaScript Cheat Sheet

Get the Async JavaScript Cheat Sheet (PDF), a printable reference to the event loop, promises, async/await, Promise combinators, error handling, fetch, AbortController, and async iteration:

Async JavaScript Cheat Sheet

Want a guided path instead of a reference? Start learning at realjs.com.

The Event Loop

  • JavaScript runs one call stack at a time
  • Microtasks (promise callbacks) run before the next macrotask (timers, I/O)
  • await pauses only its own function
Language: JavaScript Filename: Predict the Order
console.log("1 sync");
setTimeout(() => console.log("4"), 0);
Promise.resolve()
  .then(() => console.log("3"));
queueMicrotask(() => console.log("3b"));
console.log("2 sync");
// 1 sync, 2 sync, 3, 3b, 4

Promises

  • A promise is pending, then fulfilled or rejected, once
  • .then() and await always resume asynchronously
Language: JavaScript Filename: Create a Promise
const delay = (ms, value) =>
  new Promise((resolve) => {
    setTimeout(resolve, ms, value);
  });
await delay(5, "done");   // "done"
Language: JavaScript Filename: Resolve From Outside
const { promise, resolve } =
  Promise.withResolvers();
setTimeout(resolve, 1, "later");
await promise;            // "later"
Language: JavaScript Filename: Sleep in Node.js
import { setTimeout as sleep }
  from "node:timers/promises";
await sleep(1000);        // Waits 1s

async / await

Language: JavaScript Filename: Await in Sequence or in Parallel
// Sequential: ~2s total
const a = await delay(1000, "a");
const b = await delay(1000, "b");

// Parallel: ~1s total
const [x, y] = await Promise.all([
  delay(1000, "x"),
  delay(1000, "y"),
]);
Language: JavaScript Filename: Async Functions Return Promises
async function load() {
  return 42;
}
load();                   // Promise { 42 }
await load();             // 42

Combinators

Method Settles when…
all All fulfill, or 1 rejects
allSettled All settle, never rejects
any First fulfills
race First settles
Language: JavaScript Filename: Collect Every Outcome
await Promise.allSettled([
  Promise.resolve(1),
  Promise.reject(new Error("x")),
]);
// [{ status: "fulfilled", value: 1 },
//  { status: "rejected",
//    reason: Error: x }]
Language: JavaScript Filename: First Success Wins
await Promise.any([
  Promise.reject(new Error("x")),
  delay(1, "ok"),
]);                       // "ok"
await Promise.race([
  delay(10, "slow"),
  delay(1, "fast"),
]);                       // "fast"

Error Handling

  • A rejected promise needs a handler, or Node.js exits
  • Promise.any rejects with an AggregateError
Language: JavaScript Filename: try / catch / finally
try {
  await Promise.reject(new Error("boom"));
} catch (err) {
  console.log(err.message);  // boom
} finally {
  console.log("cleanup");    // cleanup
}
Language: JavaScript Filename: Chain Handlers
await fetchUser()
  .catch((err) => fallback)
  .finally(() => spinner.hide());
Language: JavaScript Filename: Catch Unhandled Rejections
process.on("unhandledRejection", (r) => {
  console.error("Lost:", r.message);
});
Promise.reject(new Error("oops"));
// Lost: oops

fetch

  • fetch() rejects on network errors, not on HTTP 404 or 500
  • Always check res.ok before parsing
Language: JavaScript Filename: Fetch JSON Safely
async function getJson(url, signal) {
  const res = await fetch(url, { signal });
  if (!res.ok) {
    throw new Error(`HTTP ${res.status}`);
  }
  return res.json();
}
await getJson(url);       // { id: 1 }
// Missing page: Error: HTTP 404
Language: JavaScript Filename: Fetch Many in Parallel
const users = await Promise.all(
  ids.map((id) => getJson(`/u/${id}`)),
);

Cancellation

Language: JavaScript Filename: Time Out a Request
try {
  await fetch(url, {
    signal: AbortSignal.timeout(3000),
  });
} catch (err) {
  console.log(err.name);  // TimeoutError
}
Language: JavaScript Filename: Abort Manually
const ctrl = new AbortController();
const req = fetch(url, {
  signal: ctrl.signal,
});
ctrl.abort();
await req;                // AbortError
Language: JavaScript Filename: Combine Signals
const signal = AbortSignal.any([
  ctrl.signal,
  AbortSignal.timeout(5000),
]);
await getJson(url, signal);

Async Iteration

  • for await consumes streams and paged APIs one item at a time
  • Async generators yield values over time
Language: JavaScript Filename: Write an Async Generator
async function* ticks(n) {
  for (let i = 0; i < n; i++) {
    await sleep(100);
    yield i;
  }
}
Language: JavaScript Filename: Consume With for await
for await (const t of ticks(3)) {
  console.log(t);         // 0, 1, 2
}
Language: JavaScript Filename: Stream a Response Body
const res = await fetch(url);
for await (const chunk of res.body) {
  console.log(chunk.length);
}
Language: JavaScript Filename: forEach Ignores await
ids.forEach(async (id) => {
  await save(id);
});
console.log("done");  // Logs first
// In order: for (const id of ids)
//   await save(id);
await Promise.all(    // In parallel
  ids.map((id) => save(id)),
);

You can download this information as a printable cheat sheet:

Free Bonus: Async JavaScript Cheat Sheet

Get the Async JavaScript Cheat Sheet (PDF), a printable reference to the event loop, promises, async/await, Promise combinators, error handling, fetch, AbortController, and async iteration:

Async JavaScript Cheat Sheet