Syntax Cache
BlogMethodFeaturesHow It WorksBuild a Game
  1. Home
  2. Cheat Sheets
  3. JavaScript
  4. JavaScript Async/Await Cheat Sheet
JavaScriptCheat Sheet

JavaScript Async/Await Cheat Sheet

Quick-reference for async/await patterns. Each section includes copy-ready snippets with inline output comments.

On this page
  1. 1Async Function Basics
  2. 2Error Handling with try/catch
  3. 3Parallel: Promise.all
  4. 4Partial Success: Promise.allSettled
  5. 5Race and Any
  6. 6Sequential vs Parallel Execution
  7. 7Cancellation: AbortController
  8. 8Async Iteration: for await...of
  9. 9Common Async Patterns
Async Function BasicsError Handling with try/catchParallel: Promise.allPartial Success: Promise.allSettledRace and AnySequential vs Parallel ExecutionCancellation: AbortControllerAsync Iteration: for await...ofCommon Async Patterns

Async Function Basics

An async function always returns a Promise. await pauses execution until the Promise settles, then unwraps the value.

async function declaration
async function fetchData(url) {
  const res = await fetch(url);
  return res.json();  // auto-wrapped in Promise
}
async arrow function
const fetchData = async (url) => {
  const res = await fetch(url);
  return res.json();
};
async always returns a Promise
async function greet() {
  return 'hello';
}
greet()           // => Promise { 'hello' }
await greet()     // => 'hello'

Even returning a plain value wraps it in a resolved Promise. Forgetting await gives you the Promise object, not the value.

Top-level await (ES modules)
// In an ES module (.mjs or type: "module")
const data = await fetch('/api/config').then(r => r.json());
console.log(data);

Error Handling with try/catch

Wrap await in try/catch to handle rejections. Without it, unhandled rejections crash Node.js (v15+) or log silently in browsers.

Basic try/catch
try {
  const data = await fetchData('/api/users');
  process(data);
} catch (err) {
  console.error('Request failed:', err.message);
}
return vs return await in try/catch
// BUG: rejection bypasses catch
async function bad() {
  try {
    return fetch('/api');  // returns pending Promise
  } catch (err) {
    return fallback;       // never runs!
  }
}

// CORRECT: await so catch can handle rejection
async function good() {
  try {
    return await fetch('/api');
  } catch (err) {
    return fallback;  // runs on rejection
  }
}

Inside try/catch, always use return await. Outside try/catch, return await is redundant.

Unhandled rejection warning
async function oops() {
  throw new Error('Something broke');
}

oops();  // No await, no .catch()
// UnhandledPromiseRejection warning!

// Fix: always handle rejections
oops().catch(console.error);

Parallel: Promise.all

Run independent async operations in parallel. Fails fast — if any Promise rejects, the whole result rejects.

Parallel fetch
const [user, posts] = await Promise.all([
  fetchUser(id),
  fetchPosts(id),
]);
Map + Promise.all pattern
const urls = ['/api/a', '/api/b', '/api/c'];
const results = await Promise.all(
  urls.map(url => fetch(url).then(r => r.json()))
);
Fail-fast behavior
try {
  const [a, b] = await Promise.all([
    fetch('/api/a'),  // succeeds
    fetch('/api/b'),  // rejects
  ]);
} catch (err) {
  // Entire Promise.all rejects on first failure
  console.error(err);
}

If any one Promise rejects, you lose all results. Use Promise.allSettled when partial success is OK.

Partial Success: Promise.allSettled

Waits for all Promises to settle (fulfill or reject). Returns an array of result objects with status, value, or reason.

Handle mixed results
const results = await Promise.allSettled([
  fetch('/api/users'),
  fetch('/api/posts'),   // might fail
  fetch('/api/settings'),
]);

for (const result of results) {
  if (result.status === 'fulfilled') {
    process(result.value);
  } else {
    console.error('Failed:', result.reason);
  }
}
Extract fulfilled values only
const results = await Promise.allSettled(promises);
const successes = results
  .filter(r => r.status === 'fulfilled')
  .map(r => r.value);

Race and Any

Promise.race settles with whichever Promise finishes first. Promise.any waits for the first fulfillment, ignoring rejections.

Timeout with Promise.race
function timeout(ms) {
  return new Promise((_, reject) =>
    setTimeout(() => reject(new Error('Timeout')), ms)
  );
}

const data = await Promise.race([
  fetch('/api/data').then(r => r.json()),
  timeout(5000),
]);
Promise.any — first success wins
try {
  const fastest = await Promise.any([
    fetch('https://cdn1.example.com/data'),
    fetch('https://cdn2.example.com/data'),
  ]);
  const data = await fastest.json();
} catch (err) {
  // AggregateError: all promises rejected
  console.log(err.errors);
}
Comparison table
// Promise.all       — all must fulfill (fail-fast)
// Promise.allSettled — wait for all, report each
// Promise.race      — first to settle (fulfill or reject)
// Promise.any       — first to fulfill (ignore rejections)

Sequential vs Parallel Execution

Sequential awaits in loops run one at a time. For independent work, use Promise.all for parallelism.

Sequential (for...of)
// Each iteration waits for the previous one
for (const url of urls) {
  const data = await fetch(url);
  await processData(data);
}
Parallel (map + Promise.all)
// All requests fire simultaneously
const results = await Promise.all(
  urls.map(async url => {
    const res = await fetch(url);
    return res.json();
  })
);
forEach does NOT await
// BUG: forEach ignores async callbacks
urls.forEach(async (url) => {
  await fetch(url);  // fires but is not awaited
});
console.log('Done!');  // runs immediately!

// Fix: use for...of or Promise.all
for (const url of urls) {
  await fetch(url);
}

forEach returns undefined, not a Promise. It cannot await async callbacks. Use for...of or map + Promise.all.

Cancellation: AbortController

Cancel in-flight fetch requests using AbortController. Essential for component unmounts, superseded requests, and timeouts.

Cancel a fetch request
const controller = new AbortController();

const promise = fetch('/api/data', {
  signal: controller.signal,
});

// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);

try {
  const res = await promise;
  const data = await res.json();
} catch (err) {
  if (err.name === 'AbortError') {
    console.log('Request cancelled');
  } else {
    throw err;
  }
}
React useEffect cleanup pattern
useEffect(() => {
  const controller = new AbortController();

  async function loadData() {
    const res = await fetch(url, { signal: controller.signal });
    setData(await res.json());
  }
  loadData().catch(() => {});

  return () => controller.abort();  // cancel on unmount
}, [url]);

Async Iteration: for await...of

Iterate over async iterables like ReadableStreams, async generators, or any object with [Symbol.asyncIterator].

Stream processing
const response = await fetch('/api/stream');
const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  console.log(decoder.decode(value));
}
Async generator
async function* paginate(url) {
  let page = 1;
  while (true) {
    const res = await fetch(`${url}?page=${page}`);
    const data = await res.json();
    if (data.length === 0) return;
    yield data;
    page++;
  }
}

for await (const page of paginate('/api/items')) {
  process(page);
}
for await...of with async iterable
for await (const chunk of readableStream) {
  process(chunk);
}

for await...of only works inside async functions. The iterable must implement [Symbol.asyncIterator].

Common Async Patterns

Practical patterns for real-world async JavaScript.

Async IIFE
(async () => {
  const data = await fetch('/api/config').then(r => r.json());
  console.log(data);
})();

Less needed with top-level await in ES modules, but still common in scripts and legacy code.

Retry with exponential backoff
async function retry(fn, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try {
      return await fn();
    } catch (err) {
      if (i === attempts - 1) throw err;
      await new Promise(r => setTimeout(r, 2 ** i * 1000));
    }
  }
}

const data = await retry(() => fetch('/api/flaky'));
Debounced async search
let controller;
async function search(query) {
  controller?.abort();
  controller = new AbortController();

  const res = await fetch(
    `/api/search?q=${query}`,
    { signal: controller.signal }
  );
  return res.json();
}
Learn JavaScript in Depth
JavaScript Error Handling Practice →JavaScript Functions Practice →JavaScript Loops Practice →
Warm-up1 / 2

Can you write this from memory?

Create a Promise that resolves to "Success".

See Also
ES6+ Features →DOM Manipulation →

Start Practicing JavaScript

Free daily exercises with spaced repetition. No credit card required.

← Back to JavaScript Syntax Practice
Syntax Cache

Build syntax muscle memory with spaced repetition.

Product

  • Pricing
  • Our Method
  • Daily Practice
  • Design Patterns
  • Interview Prep

Resources

  • Blog
  • Compare
  • Cheat Sheets
  • Vibe Coding
  • Muscle Memory

Languages

  • Python
  • JavaScript
  • TypeScript
  • Rust
  • SQL
  • GDScript

Legal

  • Terms
  • Privacy
  • Contact

© 2026 Syntax Cache

Cancel anytime in 2 clicks. Keep access until the end of your billing period.

No refunds for partial billing periods.