Skip to content

Callbacks

A callback is a function you pass to another function, to be called later when an operation completes. This was JavaScript’s original approach to async work — pass a function, and the runtime will call it when the result is ready.

setTimeout(function() {
console.log('This runs after 1 second');
}, 1000);

The second argument to setTimeout is a callback. You hand control to the runtime and your function is called back when the timer fires.

Node’s built-in APIs use a consistent signature for callbacks:

fs.readFile('data.txt', 'utf8', function(err, data) {
if (err) {
console.error('Read failed:', err.message);
return;
}
console.log('File contents:', data);
});

The pattern is (err, data) — error always first, result second. If the operation succeeded, err is null. If it failed, err is an Error object and data is undefined.

Always check err before using data. If you ignore a non-null err and try to use data, you will get confusing errors.

When one async operation depends on the result of another, you nest callbacks:

step1(function(err, resultA) {
if (err) return handleError(err);
step2(resultA, function(err, resultB) {
if (err) return handleError(err);
step3(resultB, function(err, resultC) {
if (err) return handleError(err);
console.log('Final:', resultC);
});
});
});

This deep nesting — sometimes called callback hell or the pyramid of doom — is hard to read and error-prone. Promises and async/await (covered in the next lessons) solve this.

The snippet below simulates two async steps using setTimeout. Each step uses the error-first callback pattern. Run it to see the output order.

JavaScript

The output is always Step 1 done: result-A then Step 2 done: result-B — each step fires only after the previous one completes.

What is the correct signature for a Node.js error-first callback?
In the error-first callback pattern, what value does err hold on success?
What is "callback hell"?