DevPath · Learn to code ESPTEN

Node.js: runtime, modules and async

Asynchrony in Node

The problem: slow operations

Almost everything interesting in a backend is asynchronous: reading a file, talking to a database, calling another API. Node has had three styles to handle it, and it is worth knowing all three.

1. Callbacks and the (err, data) pattern

Node's original style: you pass a continuation function (callback) that Node calls when it finishes. By convention, the first argument is the error (or null if everything went fine) and the second, the data:

const fs = require("fs");
fs.readFile("data.txt", "utf8", (err, data) => {
  if (err) {
    console.error("Failed:", err.message);
    return;            // always check err first!
  }
  console.log(data);
});

The problem: nesting several callbacks leads to "callback hell", pyramid-shaped code that is hard to read and to handle errors in.

2. Promises

A promise represents a value that will be available in the future. It is chained with .then() (success) and .catch() (error), in a flat way:

const fs = require("fs/promises"); // promise-based version of fs
fs.readFile("data.txt", "utf8")
  .then((data) => console.log(data))
  .catch((err) => console.error(err.message));

3. async / await

It is syntactic sugar over promises: you write asynchronous code that reads like synchronous code. An async function always returns a promise, and await pauses until the promise resolves. Errors are caught with a normal try / catch:

import { readFile } from "fs/promises";

async function read(path) {
  try {
    const data = await readFile(path, "utf8");
    return data;
  } catch (err) {
    console.error("Could not read:", err.message);
    throw err; // or return a default value
  }
}

In this module's exercise you will write async functions that receive a data source and await it with await. This way you practice the asynchronous flow without depending on real files (which do not exist in this environment).

Examples

An async function returns a promise; you await it with await

async function double(n) {
  return n * 2; // even without await, it returns a promise
}
const r = await double(21);
console.log(r); // 42
Put this into practice

DevPath is a hands-on course: you read the theory here; in the app you put it into practice with exercises that really run, offline.

Start free in the app →
← Modules and npmView the module →