async/await

The Default Way to Write Async Node Code

async/await

async functions return promises. await pauses execution until a promise resolves. The default style for Node.

3 min read Level 1/5 #nodejs#async#await
What you'll learn
  • Write async functions
  • Await sequentially and in parallel
  • Handle errors with try/catch

async/await is sugar over promises. Same machinery — far better syntax.

A Basic Function

import { readFile } from "node:fs/promises";

async function loadConfig() {
  const text = await readFile("config.json", "utf8");
  return JSON.parse(text);
}

const config = await loadConfig();
  • async on a function → it always returns a promise
  • await pauses until the promise settles
  • return value resolves the promise; throw err rejects it

Sequential

async function run() {
  const a = await readFile("a.txt", "utf8");   // wait
  const b = await readFile("b.txt", "utf8");   // then wait
  return a + b;
}

Total time: file A + file B (each step waits for the previous).

Parallel

async function run() {
  const [a, b] = await Promise.all([
    readFile("a.txt", "utf8"),
    readFile("b.txt", "utf8"),
  ]);
  return a + b;
}

Total time: max(A, B). Use parallel whenever steps don’t depend on each other.

Errors

async function safeRead(p) {
  try {
    return await readFile(p, "utf8");
  } catch (err) {
    if (err.code === "ENOENT") return null;
    throw err;
  }
}

try/catch works the same as sync code. Reject = throw.

Top-Level Await

In ESM modules, await works at the top level — no wrapper needed:

// app.mjs
import { readFile } from "node:fs/promises";

const config = JSON.parse(await readFile("config.json", "utf8"));
console.log(config);

For CJS scripts: wrap in an async IIFE — (async () => { ... })().

A Forever Gotcha

forEach doesn’t await:

async function run() {
  files.forEach(async (f) => {
    await process(f);   // each is fire-and-forget!
  });
  console.log("done");  // runs *before* the processing finishes
}

Use a regular for...of:

for (const f of files) {
  await process(f);
}

Or Promise.all(files.map(process)) for parallel.

promisify →