Callbacks
Introduction
JavaScript is single-threaded, meaning it can only run one line of code at a time. But real programs need to handle asynchronous (async) operations — tasks that take time, such as:
- Fetching data from a server
- Waiting for a timer
- Reading files
Asynchronous means the program doesn’t stop and wait. Instead, it continues running other code while the async task is completed in the background. Once it’s done, a callback (or later a promise) is used to handle the result.
Callbacks were the first main way to handle async work in JavaScript.
Concepts
- A callback is a function passed into another function.
- The callback is executed later, often when an async task finishes
- Common with
setTimeout,setInterval, event listeners, and older Node.js APIs.
Examples
function fetchData(callback) {
console.log("Fetching data...");
setTimeout(() => {
const data = { id: 1, name: "Alice" };
callback(data); // call the callback after 2s
}, 2000);
}
fetchData((result) => {
console.log("Data received:", result);
});
console.log("Program continues...");
// Output order:
// "Fetching data..."
// "Program continues..."
// "Data received: { id: 1, name: 'Alice' }"
Challenges
1. delayedMessage
- Write a function delayedMessage(message, delay, callback) that prints the message after the delay, then calls the callback.
💡 Show Answer
function delayedMessage(msg, delay, callback) {
setTimeout(() => {
console.log(msg);
callback();
}, delay);
}
delayedMessage("This is the message", 1000, () =>
console.log("Callback executed!")
);
2. square with callback
- Use a callback to calculate the square of a number after 1 second.
💡 Show Answer
function square(n, callback) {
setTimeout(() => callback(n * n), 500);
}
square(5, (res) => console.log(res));
3. getUser
- Create a function
getUser(callback)that simulates returning a user object after 2 seconds.
💡 Show Answer
function getUser(cb) {
setTimeout(() => cb({ id: 1, name: "Alice" }), 500);
}
getUser((u) => console.log(u));
4. Nested steps
- Nest two callbacks so the second only runs after the first finishes.
💡 Show Answer
function firstCallback(done) {
setTimeout(() => {
console.log("First callback finished");
done();
}, 1000);
}
function secondCallback() {
console.log("Second callback finished");
}
firstCallback(() => {
secondCallback();
});
5. doSteps
- Write a function
doSteps(callback1, callback2)that executescallback1thencallback2.
💡 Show Answer
function doSteps(cb1, cb2) {
cb1();
cb2();
}
doSteps(
() => console.log("a"),
() => console.log("b")
);
6. calculate with callback
- Create a callback-based calculator that takes two numbers and a callback (add, subtract, etc.).
💡 Show Answer
function calc(a, b, cb) {
return cb(a, b);
}
console.log(calc(2, 3, (x, y) => x + y));
console.log(calc(2, 3, (x, y) => x * y));
console.log(calc(2, 3, (x, y) => x - y));
console.log(calc(2, 3, (x, y) => x / y));
7. Async order demo
- Demonstrate async behavior: log "Start", then use setTimeout to log "Later", then log "End".
- Which prints first?
💡 Show Answer
console.log("Start");
setTimeout(() => console.log("Later"), 500);
console.log("End");
8. fake fetch
- Write a function that fetches fake data (using setTimeout) and then calls a callback to display it.
💡 Show Answer
function fetchData(cb) {
setTimeout(() => cb({ data: "hi" }), 500);
}
fetchData((r) => console.log(r.data));
9. addEventListener
- Show how callbacks are used in addEventListener.
💡 Show Answer
document.body.addEventListener("click",()=>console.log("clicked"));
10. mapArray
- Write your own mapArray(arr, callback) function that applies the callback to each element.
💡 Show Answer
function mapArray(arr, cb) {
let out = [];
for (let i of arr) out.push(cb(i));
return out;
}
console.log(mapArray([1, 2, 3], (x) => x * 2));
console.log(mapArray([1, 2, 3], (x) => x + 1));