Explain callbacks, "callback hell," and the error-first callback convention.

3 minbeginnernodejscallbackserror-firstcallback-hellasync

Quick Answer

A callback is a function passed to an async operation to run on completion. Node's convention is error-first: the callback's first argument is an error (or null), the rest are results. Deeply nested callbacks create hard-to-read 'callback hell', which Promises and async/await were designed to flatten.

Detailed Answer

Answer:

Callbacks are the original async pattern in Node — you pass a function that runs when the operation finishes.

Error-first convention: Node core callbacks take (err, ...results). Always check err first:

fs.readFile('data.txt', 'utf8', (err, data) => {
  if (err) return handleError(err); // error first
  console.log(data);
});

The return on error prevents running the success path.

Callback hell — nesting async steps produces a rightward "pyramid of doom" that's hard to read and error-handle:

getUser(id, (err, user) => {
  if (err) return cb(err);
  getPosts(user.id, (err, posts) => {
    if (err) return cb(err);
    getComments(posts[0].id, (err, comments) => {
      if (err) return cb(err);
      // ...deeper and deeper
    });
  });
});

Fixes:

  • Promises + chaining flatten the nesting.
  • async/await makes async code read like synchronous code.
try {
  const user = await getUser(id);
  const posts = await getPosts(user.id);
  const comments = await getComments(posts[0].id);
} catch (err) {
  handleError(err); // one place for errors
}

Tip: you can wrap a callback API with util.promisify to use it with async/await.