JavaScript Cheatsheet

Async

Use this JavaScript reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Callbacks

The original async pattern. Still used in Node.js APIs and event listeners.

// Error-first callback convention (Node.js style)
fs.readFile("file.txt", "utf8", (err, data) => {
  if (err) return console.error(err);
  console.log(data);
});

// Simple callback
setTimeout(() => console.log("after 1s"), 1000);
setInterval(() => console.log("every 1s"), 1000);

// Clearing timers
const id = setTimeout(fn, 1000);
clearTimeout(id);
const intervalId = setInterval(fn, 1000);
clearInterval(intervalId);

Promises

A Promise is in one of three states: pending, fulfilled, or rejected. Once settled, it never changes state.

// Creating a Promise
const p = new Promise((resolve, reject) => {
  if (success) resolve(value);
  else reject(new Error("failed"));
});

// Consuming
p.then(value => console.log(value))
 .catch(err => console.error(err))
 .finally(() => console.log("done"));

// .then can chain — each returns a new Promise
fetch("/api/users")
  .then(res => res.json())        // parse JSON
  .then(users => users[0])        // extract first
  .then(user => console.log(user))
  .catch(err => console.error(err));

// .then with two callbacks (resolve, reject)
p.then(
  value => console.log("ok", value),
  err   => console.error("err", err)
);

Promise Static Methods

// Promise.resolve / reject — wrap value in settled promise
Promise.resolve(42)         // immediately fulfilled with 42
Promise.reject(new Error()) // immediately rejected

// Promise.all — all must resolve; rejects on first rejection
Promise.all([p1, p2, p3])
  .then(([v1, v2, v3]) => console.log(v1, v2, v3))
  .catch(err => console.error("any failed:", err));

// Promise.allSettled (ES2020) — waits for all, never rejects
Promise.allSettled([p1, p2, p3])
  .then(results => {
    results.forEach(r => {
      if (r.status === "fulfilled") console.log("ok:", r.value);
      else console.error("fail:", r.reason);
    });
  });

// Promise.race — first to settle wins (resolved or rejected)
Promise.race([fetch(url1), fetch(url2)])
  .then(firstResult => console.log(firstResult));

// Promise.any (ES2021) — first to FULFILL wins; rejects with AggregateError if all reject
Promise.any([p1, p2, p3])
  .then(firstFulfilled => console.log(firstFulfilled))
  .catch(err => console.error(err.errors)); // AggregateError

// Timeout pattern with race
const withTimeout = (promise, ms) =>
  Promise.race([
    promise,
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error("Timeout")), ms)
    ),
  ]);

async / await (ES2017)

async functions always return a Promise. await pauses execution of the async function until the promise settles.

// Basic pattern
async function fetchUser(id) {
  const res = await fetch(`/api/users/${id}`);
  if (!res.ok) throw new Error(`HTTP error ${res.status}`);
  return res.json(); // returns Promise<User>
}

// Arrow function
const fetchUser = async (id) => {
  const res = await fetch(`/api/users/${id}`);
  return res.json();
};

// Await unwraps the promise value
const user = await fetchUser(1); // User object, not Promise<User>

// await only works inside async functions
// Top-level await is available in ES modules (no function wrapper needed)
const data = await fetch("/api").then(r => r.json()); // top-level in modules

Error Handling in async/await

// try/catch
async function load() {
  try {
    const res = await fetch("/api/data");
    const data = await res.json();
    return data;
  } catch (err) {
    console.error("Failed:", err);
    return null;
  } finally {
    setLoading(false);
  }
}

// .catch() on the returned promise
load().catch(console.error);

// Inline error handling per-await
async function safe() {
  const data = await fetchData().catch(() => null); // null on error
  if (!data) return; // guard
  process(data);
}

Sequential vs Parallel

// Sequential — each awaits the previous (slower)
async function sequential() {
  const a = await fetchA(); // waits
  const b = await fetchB(); // waits after a
  return [a, b];
}

// Parallel — fire both, await together (faster)
async function parallel() {
  const [a, b] = await Promise.all([fetchA(), fetchB()]);
  return [a, b];
}

// Start both, await each (parallel but access separately)
async function parallel2() {
  const aPromise = fetchA();
  const bPromise = fetchB();
  const a = await aPromise;
  const b = await bPromise;
  return [a, b];
}

// Parallel over array
async function fetchAll(ids) {
  const promises = ids.map(id => fetch(`/api/${id}`).then(r => r.json()));
  return Promise.all(promises);
}

// Controlled concurrency (process N at a time)
async function batchProcess(items, concurrency = 5) {
  const results = [];
  for (let i = 0; i < items.length; i += concurrency) {
    const batch = items.slice(i, i + concurrency);
    const batchResults = await Promise.all(batch.map(process));
    results.push(...batchResults);
  }
  return results;
}

fetch API

// GET
const res = await fetch("/api/users");
const users = await res.json();

// POST with JSON
const res2 = await fetch("/api/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Alice", age: 30 }),
});
const created = await res2.json();

// Check status
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);

// Response methods
res.json()        // parse body as JSON → Promise<any>
res.text()        // body as string → Promise<string>
res.blob()        // body as Blob → Promise<Blob>
res.arrayBuffer() // body as ArrayBuffer
res.formData()    // body as FormData

// Response properties
res.status       // 200, 404, etc.
res.statusText   // "OK", "Not Found", etc.
res.ok           // true if status 200–299
res.headers      // Headers object
res.url          // final URL (after redirects)
res.redirected   // true if redirected

// Request options
fetch(url, {
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE",
  headers: { "Authorization": "Bearer token" },
  body: JSON.stringify(data) | formData | blob,
  credentials: "include",  // send cookies cross-origin
  cache: "no-cache",
  signal: controller.signal, // AbortController
  mode: "cors" | "no-cors" | "same-origin",
  redirect: "follow" | "error" | "manual",
});

AbortController

const controller = new AbortController();
const { signal } = controller;

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

try {
  const res = await fetch("/api/slow", { signal });
  const data = await res.json();
} catch (err) {
  if (err.name === "AbortError") {
    console.log("Request aborted");
  } else {
    throw err;
  }
}

// Abort multiple requests
const ac = new AbortController();
Promise.all([
  fetch(url1, { signal: ac.signal }),
  fetch(url2, { signal: ac.signal }),
]);
ac.abort(); // cancels both

Async Iteration (ES2018)

// for await...of — iterate async iterables
async function processStream(stream) {
  for await (const chunk of stream) {
    process(chunk);
  }
}

// Async generators
async function* paginate(url) {
  let page = 1;
  while (true) {
    const res = await fetch(`${url}?page=${page}`);
    const data = await res.json();
    if (!data.items.length) break;
    yield* data.items;
    page++;
  }
}

for await (const item of paginate("/api/items")) {
  console.log(item);
}

Event Loop and Microtasks

// Order: synchronous → microtasks → macrotasks
console.log("1 sync");

setTimeout(() => console.log("4 macro"), 0);  // macrotask

Promise.resolve().then(() => console.log("3 micro")); // microtask

queueMicrotask(() => console.log("2 micro"));         // microtask

// Output: 1, 2, 3, 4

// Resolved promises — microtasks
Promise.resolve(42).then(v => console.log(v)); // next microtask checkpoint
await Promise.resolve(42); // pause current, queue continuation as microtask

Common Async Patterns

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

// Deferred promise
function deferred() {
  let resolve, reject;
  const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
  return { promise, resolve, reject };
}

// Sleep / delay
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
await sleep(1000);

// Promise-ify callback API
function readFile(path) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, "utf8", (err, data) => {
      if (err) reject(err);
      else resolve(data);
    });
  });
}
// Built-in: util.promisify(fs.readFile)