How do callbacks work in JavaScript, and why are they so useful?
A callback is a function you hand to another function so it can call it later. It is how JavaScript passes behaviour into code that only knows how to do one thing. The receiving function decides when to call it and with what, and the caller decides what the behaviour is.
function run(task) {
console.log("before");
task();
console.log("after");
}
run(() => console.log("work"));
// The same function reused with different behaviour:
function applyToAll(items, fn) {
return items.map(fn);
}
console.log(applyToAll([1, 2, 3], (n) => n * 10)); // [10, 20, 30]
console.log(applyToAll([1, 2, 3], (n) => `#${n}`)); // ["#1", "#2", "#3"]Because the behaviour arrives as an argument, the receiving function stays generic. The array map method does not know anything about multiplying numbers or formatting labels. It knows how to call a function once per element and collect the results, and the caller decides what that function does. That separation is the reason higher-order functions became the backbone of functional style in the language.
Callbacks also carry the notion of timing. The callback is not necessarily called immediately. It might be called later, after a timer, after a network response, or after a user event. The receiving function owns the schedule, and the callback just reacts when it is invoked. That is exactly how the built-in array methods work: they call your function synchronously as they walk the array, but a method such as setTimeout calls yours later.
Two practical points. A callback that is expected to be called more than once, or not at all, needs a clear contract, and the error-first convention is the traditional way to signal failure. And a callback that is passed straight through to another API should be wrapped in an arrow function when you need to add behaviour, so the extra arguments do not leak through.