Skip to main content

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 executes callback1 then callback2.
💡 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));