Callback Functions

Functions passed as arguments. The foundation of async JavaScript.

What Are Callbacks?

A function passed to another function to be called later.

function greet(name, callback) {
  const message = "Hello, " + name;
  callback(message);
}

function log(text) {
  console.log(text);
}

greet("Alice", log);
// "Hello, Alice"

'log' is passed as a callback. greet() calls it when the message is ready.

1 / 2

Synchronous Callbacks

Executed immediately within the calling function.

// Array methods use sync callbacks:
const nums = [1, 2, 3, 4, 5];

nums.forEach((n) => console.log(n));  // logs each
nums.map((n) => n * 2);               // [2, 4, 6, 8, 10]
nums.filter((n) => n > 3);            // [4, 5]
nums.find((n) => n === 3);            // 3
nums.sort((a, b) => a - b);           // sorted

// .filter() with a callback:

"apple""banana""cherry"

Async Callbacks

Executed later, when an operation completes.

// setTimeout — callback runs after delay:
setTimeout(() => {
  console.log("2 seconds passed!");
}, 2000);

// Event listener — callback runs on event:
button.addEventListener("click", () => {
  console.log("Clicked!");
});

// File reading (Node.js):
fs.readFile("data.txt", (err, data) => {
  console.log(data);
});

// setTimeout demo:

Error-First Pattern

Node.js convention: first parameter is always the error.

// Error-first callback pattern:
fs.readFile("data.txt", (err, data) => {
  if (err) {
    console.error("Failed:", err.message);
    return;
  }
  console.log("Got:", data);
});

// Creating your own:
function fetchUser(id, callback) {
  if (!id) {
    callback(new Error("ID required"), null);
    return;
  }
  // ... fetch logic
  callback(null, userData); // success: err=null
}

Convention rules:

  • First parameter is always err (or null on success)
  • Always check err before using data
  • Return early after handling error to avoid running success code

Callback Hell

Nested callbacks make code hard to read and maintain.

✗ Callback hell

getUser(id, (err, user) => {
  getPosts(user.id, (err, posts) => {
    getComments(posts[0], (err, comments) => {
      render(comments, (err) => {
        // 😵 deeply nested
      });
    });
  });
});

✓ Modern alternative (Promises)

// Flat and readable:
const user = await getUser(id);
const posts = await getPosts(user.id);
const comments = await getComments(posts[0]);
await render(comments);

💡 Callbacks are still fundamental to understand, but modern JavaScript uses Promises and async/await for cleaner async code.

FAQ

Common questions about callbacks.