What are callbacks in JavaScript and how to avoid callback hell

· Category: JavaScript

Short answer

A callback is a function passed into another function to be executed later. Deep nesting of callbacks creates "callback hell," which Promises and async/await solve by flattening control flow.

How it works

Synchronous code runs top-to-bottom. Asynchronous operations need a way to resume logic once complete, so they accept a callback:

readFile("config.json", (err, data) => {
  if (err) return console.error(err);
  parseConfig(data, (err, config) => {
    if (err) return console.error(err);
    initApp(config, (err) => {
      // deeply nested
    });
  });
});

Example

Refactor to Promises:

readFilePromise("config.json")
  .then(parseConfig)
  .then(initApp)
  .catch(console.error);

Or with async/await:

const data = await readFilePromise("config.json");
const config = await parseConfig(data);
await initApp(config);

Why it matters

Flat code is easier to read, debug, and maintain. Modern JavaScript avoids deep callbacks in favor of Promise-based APIs.