Node's APIs were designed with error-first callbacks: (err, result) => {}. If err is truthy, handle the error; otherwise use result. Promises and async/await wrap these today, but legacy code and some core patterns still use callbacks.
Error-first pattern
import fs from 'node:fs';
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
console.log(data);
});
Callback hell
Nested callbacks for sequential async steps become hard to read—promises and async/await flatten the flow. Recognize callbacks in older tutorials and npm docs.
Important interview questions and answers
- Q: Why error-first?
A: Convention ensures errors are never ignored as a forgotten return value—first argument is always err or null. - Q: util.promisify?
A: Converts callback-style functions to promise-returning wrappers for async/await.
Self-check
- In error-first callbacks, what does a truthy first argument mean?
- Why prefer promises for new code?