Q7 of 40 · JavaScript

What is a callback function, and why are they common in JavaScript?

JavaScriptJuniorjavascriptcallbacksasyncevent-loopnode

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
    });
  });
});

// WHAT INTERVIEWERS LOOK FOR

Understanding of why callbacks exist (single-threaded non-blocking model), the error-first convention, and callback hell as the motivation for Promises. Connecting to async patterns in test frameworks earns extra credit.

// COMMON PITFALL

Passing `fn()` (invoked immediately) instead of `fn` (reference) as a callback — the function runs right away and its return value (likely undefined) is passed instead of the function itself.