How to Use Callback Functions in JavaScript

Use callback functions when one function should run after another function finishes or when behavior should be passed in as reusable logic. Callbacks are common in array methods, timers, event handlers, and async flows.

What you’ll build or solve

You’ll learn how to use callback functions in JavaScript by passing one function into another. You’ll also know how callbacks improve reuse and sequencing.

When this approach works best

This approach is the right choice when the next action depends on a previous function call.

Common real-world scenarios include:

  • Array methods
  • Timers
  • Button click handlers
  • API response handlers
  • Custom reusable utilities

This is a bad idea when the flow becomes deeply nested. In that case, promises or async/await are usually cleaner.

Prerequisites

You only need:

  • A JavaScript file or browser console
  • Basic functions knowledge

Step-by-step instructions

Step 1: Pass a function as an argument and call it later

Create a function that accepts another function as a parameter.

JavaScript

function processUser(name, callback) {
  const message = `Hello, ${name}`;
  callback(message);
}

Then pass a callback when calling it.

JavaScript

processUser("Alex", function (message) {
  console.log(message);
});

Arrow functions work especially well for short callbacks.

JavaScript

processUser("Mia", (message) => {
  console.log(message);
});

What to look for:

  • Pass the function reference, not the result
  • Call the callback inside the parent function
  • Great for sequencing actions
  • Common in timers and array methods
  • Arrow functions keep callback code shorter

Examples you can copy

Array callback

JavaScript

const numbers = [1, 2, 3];

numbers.forEach((num) => {
  console.log(num);
});

Timer callback

JavaScript

setTimeout(() => {
  console.log("Done");
}, 1000);

Reusable logger

JavaScript

function runTask(callback) {
  callback();
}

Common mistakes and how to fix them

Mistake 1: Calling the callback too early

What the reader might do:

JavaScript

processUser("Alex", console.log());

Why it breaks: console.log() runs immediately, and its result gets passed instead of the function.

Corrected approach:

JavaScript

processUser("Alex", console.log);

Or wrap it.

JavaScript

processUser("Alex", (message) => console.log(message));

Mistake 2: Forgetting to call the callback inside the function

What the reader might do:

JavaScript

function runTask(callback) {
  callback;
}

Why it breaks: the callback is referenced but never executed.

Corrected approach:

JavaScript

function runTask(callback) {
  callback();
}

Mistake 3: Deep nested callback chains

What the reader might do:

JavaScript

task1(() => {
  task2(() => {
    task3(() => {});
  });
});

Why it breaks: deeply nested callbacks quickly become hard to read.

Corrected approach:

Refactor to promises or split callbacks into named functions.

Troubleshooting

If the callback runs immediately, pass the function reference instead of calling it.

If nothing happens, check whether the callback is actually invoked.

If nested callbacks become messy, switch to promises or async/await.

If callback arguments are missing, verify the parent function passes them in.

Quick recap

  • Pass functions as arguments
  • Call them later inside another function
  • Great for sequencing and reuse
  • Pass the function reference, not the result
  • Use promises when nesting gets too deep