Q7 of 40 · JavaScript
What is a callback function, and why are they common in JavaScript?
Short answer
Short answer: A callback is a function passed as an argument and invoked after an operation completes. JavaScript's single-threaded, non-blocking model uses callbacks (and later Promises/async-await) to handle async operations like timers, events, and HTTP requests without blocking the main thread.
Detail
A callback is simply a function you pass to another function to be called at some point — usually when an asynchronous operation completes.
Why JavaScript uses them: JavaScript runs on a single thread. If it blocked waiting for a network request, the UI would freeze. Instead, JS starts the operation, registers a callback, and continues executing. When the operation completes, the callback is placed on the event queue and called when the call stack is empty.
Error-first callbacks (Node.js style): The Node.js convention passes the error as the first argument: (err, result) => {}. Callers must check err before using result — forgetting this check is a common source of silent test failures.
Callback hell: Deeply nested callbacks for sequential async operations become hard to read and maintain. This led to the introduction of Promises and async/await as more composable alternatives.
In Playwright/Cypress: page.on('requestfinished', callback) event listeners use callbacks. Playwright uses Promises throughout. Understanding callbacks helps you debug Node-style APIs and event handlers in test code.
// EXAMPLE
// Synchronous callback
[1, 2, 3].forEach(n => console.log(n * 2));
// Async callback (timer)
setTimeout(() => console.log("later"), 1000);
// Node.js error-first callback style
const fs = require("fs");
fs.readFile("data.txt", "utf8", (err, data) => {
if (err) throw err; // always handle error first
console.log(data);
});
// "Callback hell" — readability degrades with nesting
doStep1((err, r1) => {
doStep2(r1, (err, r2) => {
doStep3(r2, (err, r3) => {
console.log(r3); // hard to follow, hard to handle errors
});
});
});