Callbacks
The callback pattern
Section titled “The callback pattern”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.
The error-first convention
Section titled “The error-first convention”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.
Callback nesting
Section titled “Callback nesting”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.
Runnable demo
Section titled “Runnable demo”The snippet below simulates two async steps using setTimeout. Each step uses the error-first callback pattern. Run it to see the output order.
The output is always Step 1 done: result-A then Step 2 done: result-B — each step fires only after the previous one completes.