Callbacks
A callback is a function you pass to another function, to be called later. Because JavaScript functions are values, you can hand them around like numbers or strings.
function greet(name, formatter) {
console.log(formatter(name));
}
greet("Asha", (n) => `Hello, ${n}!`);
greet("Leo", (n) => n.toUpperCase());You've already used callbacks
const nums = [5, 2, 9, 1];
nums.forEach((n) => console.log("item", n));
console.log(nums.map((n) => n * 10));
console.log([...nums].sort((a, b) => a - b));forEach, map, filter and sort all take callbacks: you supply the "what", they handle the looping.
Writing a higher-order function
A function that takes (or returns) a function is a higher-order function:
function repeat(times, action) {
for (let i = 1; i <= times; i++) {
action(i);
}
}
repeat(3, (i) => console.log(`Round ${i}`));function myFilter(array, test) {
const result = [];
for (const item of array) {
if (test(item)) result.push(item);
}
return result;
}
console.log(myFilter([3, 8, 12, 5, 20], (n) => n > 6));
console.log(myFilter(["apple", "kiwi", "fig"], (w) => w.length <= 4));That's essentially how Array.prototype.filter works.
Asynchronous callbacks
Callbacks also say "run this when something finishes": a timer, a click, a download:
console.log("1: before");
setTimeout(() => console.log("3: after 500 ms"), 500);
console.log("2: right away");The program doesn't wait; the callback runs later, when the timer fires.
Callback hell
When each step depends on the previous one finishing, callbacks nest deeper and deeper:
setTimeout(() => {
console.log("step 1 done");
setTimeout(() => {
console.log("step 2 done");
setTimeout(() => {
console.log("step 3 done");
}, 200);
}, 200);
}, 200);Add error handling at every level and it becomes unreadable. This "pyramid of doom" is why JavaScript added Promises and async/await, covered in the asynchronous module.