Callbacks
A callback is a function passed into another function to be called later.
You have already seen callbacks with array methods:
const numbers = [1, 2, 3];
const doubled = numbers.map((number) => number * 2);The function passed to map is a callback.
In asynchronous programming, callbacks are often used to run code after something finishes.
Callback Basics
function greet(name, callback) {
const message = `Hello, ${name}`;
callback(message);
}
greet("Alice", (message) => {
console.log(message);
});Output:
Hello, AliceThe callback lets greet decide when to run your function.
Async Callback Example
console.log("Start");
setTimeout(() => {
console.log("Timer finished");
}, 1000);
console.log("End");Output:
Start
End
Timer finishedThe callback passed to setTimeout runs later.
Callbacks With Events
Browser events use callbacks.
button.addEventListener("click", () => {
console.log("Button clicked");
});The callback runs when the user clicks.
You do not call it yourself.
The browser calls it later.
Named Callback Functions
Callbacks do not have to be inline.
function handleClick() {
console.log("Button clicked");
}
button.addEventListener("click", handleClick);Named callbacks can make code easier to read and reuse.
Do not call the function when passing it:
button.addEventListener("click", handleClick); // correct
button.addEventListener("click", handleClick()); // wrongThe second version calls handleClick immediately.
Callback Parameters
The function that runs the callback decides what arguments to pass.
function loadUser(callback) {
const user = {
id: 1,
name: "Alice",
};
callback(user);
}
loadUser((user) => {
console.log(user.name);
});Output:
AliceError-First Callbacks
Older Node.js APIs often use error-first callbacks.
The first callback argument is an error.
The second argument is the result.
function readData(callback) {
const success = true;
if (!success) {
callback(new Error("Could not read data"));
return;
}
callback(null, { name: "Alice" });
}
readData((error, data) => {
if (error) {
console.log(error.message);
return;
}
console.log(data.name);
});This pattern makes success and failure explicit.
Modern code often uses promises instead, but you will still see callbacks in older APIs and event systems.
Callbacks and this
When passing object methods as callbacks, this can be lost.
const user = {
name: "Alice",
greet() {
console.log(`Hello, ${this.name}`);
},
};
setTimeout(user.greet, 1000); // this may be lostUse a wrapper:
setTimeout(() => {
user.greet();
}, 1000);Or bind the method:
setTimeout(user.greet.bind(user), 1000);This connects back to the this module.
Best Practices
Use callbacks when an API expects them, such as events.
Use named callbacks when inline functions become too long.
Do not call the callback while passing it unless the API expects a returned function.
Handle errors explicitly in error-first callbacks.
Keep callback logic small.
Common Mistakes
Mistake 1: Calling Instead of Passing
setTimeout(showMessage(), 1000);This calls showMessage immediately.
Correct:
setTimeout(showMessage, 1000);or:
setTimeout(() => showMessage(), 1000);Mistake 2: Ignoring Callback Errors
readData((error, data) => {
console.log(data.name);
});If error exists, data may be missing.
Handle the error first.
Mistake 3: Making Callbacks Too Deep
Nested callbacks quickly become hard to read.
You will learn this as callback hell in the next lesson.
Summary
Callbacks are functions passed to other functions to run later.
- Callbacks are used in arrays, events, timers, and older async APIs.
- The caller decides when to run the callback.
- Error-first callbacks pass
(error, data). - Do not call a callback while passing it unless intended.
- Passing methods as callbacks can lose
this. - Deeply nested callbacks can become hard to maintain.