Explain callbacks, "callback hell," and the error-first callback convention.
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.