Script Valley
Node.js: The Complete Runtime
Async JavaScript in Node.jsLesson 2.1

Callbacks in Node.js and the error-first convention

callback pattern, error-first callbacks, callback hell, Node.js core callback APIs, fs.readFile, asynchronous vs synchronous fs

The Error-First Callback Pattern

Node.js core APIs use a strict convention: callback functions receive (error, result) as their first two arguments. Always check the error before using the result.

const fs = require('fs');

fs.readFile('./data.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Read failed:', err.message);
    return; // return here or code continues
  }
  console.log(data);
});

Never Use Sync APIs in Servers

Node.js provides synchronous variants of most I/O functions (fs.readFileSync, fs.writeFileSync). These block the entire event loop until they complete. One slow disk read can freeze all concurrent requests.

// BAD in a server:
const data = fs.readFileSync('./large-file.txt', 'utf8');

// GOOD:
fs.readFile('./large-file.txt', 'utf8', (err, data) => { ... });

Callback Hell

Nesting callbacks for sequential async operations creates deeply indented code that is hard to read and error-handle. This is the main reason Promises were introduced.

fs.readFile('a.txt', 'utf8', (err, a) => {
  fs.readFile('b.txt', 'utf8', (err, b) => {
    fs.writeFile('out.txt', a + b, (err) => {
      // three levels deep and growing
    });
  });
});

Recognize this pattern — you will refactor it with Promises in the next lessons.

Up next

Promises in Node.js: then, catch, and chaining

Sign in to track progress