Skip to main content

Menu

System onlineAI Tutorials / 2026

AI Tutorials
Knowledge search

Recent · Popular · Tutorials

  • dart3 tutorials
  • java1 tutorial
  • Javascript3 tutorials
  • Node.js Introduction2 tutorials
  • dartdart · General · In depth
  • JavascriptJavascript · Advanced · In depth
  • JavascriptJavascript · Advanced · Mid
  • JavascriptJavascript · Advanced · Short

Find a tutorial

Tell the assistant what you want to learn. It suggests published chapters.

For example: “I want to learn Rust ownership from the start.” The conversation is kept only in this tab.

0 / 2,000 characters

Enter to send, Shift+Enter for a new line. Do not include personal information.

Chapter 12

Working Asynchronously

In the last chapter, we saw how Node.js reads files without freezing the program. This chapter walks through the three styles you can use to write that kind of code: **callbacks** (functions you hand over to be called later), **promises** (objects representing a future result), and **async/await** (
Level: GeneralLength: Mid2 min read

Read at another depth

Working Asynchronously

In the last chapter, we saw how Node.js reads files without freezing the program. This chapter walks through the three styles you can use to write that kind of code: callbacks (functions you hand over to be called later), promises (objects representing a future result), and async/await (syntax that makes async code look normal).

What to have ready: You should have Node.js installed, know how to run a file with node filename.js, and have seen a file read with the fs module. No other background is needed.

Why asynchronous code exists

Imagine a restaurant with one waiter. A synchronous waiter takes one order, goes to the kitchen, waits for the food, delivers it, and only then takes the next order. Everyone else starves. An asynchronous waiter takes an order, hands it to the kitchen, and serves other tables while the food cooks. When the kitchen rings the bell, the waiter delivers that meal.

Computers work the same way. Reading a file or fetching a web page takes far longer than doing math. Node.js starts the slow task, keeps running other code, and comes back when the task finishes.

Style 1: Callbacks

A callback is a function you pass to another function, to be run later.

Code example in javascript
const { readFile } = require('node:fs');

readFile('notes.txt', 'utf8', (err, text) => {
  if (err) {
    console.error('Could not read file:', err.message);
    return;
  }
  console.log(text);
});

console.log('This prints first!');

The readFile call returns immediately. The message at the bottom prints before the file content. If several tasks each need the result of the previous one, callbacks nest inside callbacks. Many levels deep, this becomes hard to read — a problem developers famously called "callback hell."

Style 2: Promises

A promise is an object that stands for a value that does not exist yet. It is like a receipt number at a shop: you can't take the item home yet, but you will be able to.

Promises can be chained with .then(), which avoids deep nesting:

Code example in javascript
const { readFile } = require('node:fs/promises');

readFile('notes.txt', 'utf8')
  .then((text) => console.log(text))
  .catch((err) => console.error('Could not read file:', err.message));

.catch() runs if the task failed — like the shop telling you the item is out of stock.

Style 3: async/await

The async and await keywords let you write promise-based code that reads top to bottom, like ordinary code:

Code example in javascript
const { readFile } = require('node:fs/promises');

async function main() {
  try {
    const text = await readFile('notes.txt', 'utf8');
    console.log(text);
  } catch (err) {
    console.error('Could not read file:', err.message);
  }
}

main();

await means "pause this function until the result arrives." The keyword only works inside a function marked async, which makes the function return a promise. A try/catch block handles failures, the same way you would handle errors in regular code.

This is the style most modern Node.js code uses, and the one we recommend.

A common mistake: forgetting await

Code example in javascript
const { readFile } = require('node:fs/promises');

async function main() {
  const text = readFile('notes.txt', 'utf8'); // missing await!
  console.log(text); // prints [object Promise], not the file
}
main();

Without await, you get the receipt, not the item. The variable holds a promise object, not the text. If your output looks like [object Promise], a missing await is the first thing to check.

A flowchart showing main starting, awaiting a file read, control returning to the event loop, then resuming to print the result.
100%
Flow of an asynchronous file read in Node.js
Show diagram source
flowchart TD
    A[main starts] --> B[await readFile]
    B --> C[Function pauses]
    C --> D[Event loop runs other work]
    D --> E[File read completes]
    E --> F[Function resumes]
    F --> G[Print text]

Exercise

Why does console.log('This prints first!') run before the file content in the callback example?

Show answer

Because readFile starts the read and returns immediately without waiting. The next line of code runs right away, and the callback only runs later, once the file has been read.

Exercise

You write const data = readFile('notes.txt', 'utf8'); inside an async function and print data, but you see [object Promise]. What is wrong and how do you fix it?

Show answer

The await keyword is missing. Write const data = await readFile('notes.txt', 'utf8'); so the function pauses until the file content is ready.

Spotted a mistake, or code that does not work?

Report an issue

Chapter: Working Asynchronously

0 / 2,000 characters

Plain text, for example: the second code sample does not compile. Do not include personal information.

You can't do that