Node.js · Lesson 3 of 7

Async code: callbacks, promises & async/await

How Node handles slow work, the event loop, and writing clean async code with async/await.

Reading a file, querying a database or calling an API takes time. Node starts the work, carries on, and runs your code when the result is ready. There are three styles:

  1. Callbacks — pass a function to run later. Nesting many of them leads to “callback hell”.
  2. Promises — an object representing a future result, with .then() and .catch().
  3. async/await — write promise code that reads top to bottom. Use try/catch for errors. This is the style to use today.

To run independent tasks at the same time, start them together with Promise.all instead of awaiting one after another.

Example code

Run with Node.js 20+
// async.js
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function fetchJob(id) {
  await wait(500); // pretend this is a database call
  return { id, title: "Node.js Developer " + id };
}

async function main() {
  console.log("Start");
  const jobs = await Promise.all([fetchJob(1), fetchJob(2), fetchJob(3)]);
  jobs.forEach((j) => console.log(j.title));
  console.log("Done (about 0.5s, not 1.5s)");
}

main().catch((err) => console.error("Failed:", err.message));

Output

Start
Node.js Developer 1
Node.js Developer 2
Node.js Developer 3
Done (about 0.5s, not 1.5s)

Save the code in a file such as app.js and run node app.js. For Express lessons, run npm install express first. Names and data are fictional.

Key points

  • Node doesn't wait idle — async work finishes later.
  • Prefer async/await with try/catch.
  • Use Promise.all for independent tasks.
  • Always handle promise errors.

Quick check

Three independent API calls each take 1 second. How long does await Promise.all([a(), b(), c()]) take?

Practice task

Write an async function that 'loads' a user and their applications using two wait() calls, first one after another and then with Promise.all, and compare the timing with console.time().

Interview corner

What is the event loop?

The mechanism that lets Node run callbacks when async work completes. The call stack runs synchronous code; finished async operations queue callbacks, and the event loop moves them onto the stack when it's empty, processing promise microtasks before timers and I/O callbacks.

What happens if you don't handle a rejected promise?

Node reports an unhandled promise rejection, and in recent versions the process exits with an error. Always use try/catch with await or .catch() on promises.

Further reading

Official documentation, linked for deeper study. These are outside sites; this lesson's text is our own.

Original lesson written by the InfoparkDaily team · © 2026 InfoparkDaily · Free to learn — no paid course or subscription.