What the Hell is Callback Hell in Javascript ?

profile picture

What the Hell is Callback Hell in Javascript ?

"Callback hell" is a term I've never heard off before discussing asynchronous javascript during a job interview.

As soon as I got home, I checked it out.

Basically, when you want to write asynchronous code in javascript, you end up using multiple Promise stacked into each other. If you ever used axios, you know that you can wait for the ajax call to end and then trigger some code in the .then() callback.

Now imagine that, like in PHP, you want to execute simple javascript code in a defined order (asynchronous). The only way to do that is by using callbacks.

Look at this code example from callbackhell.com :

fs.readdir(source, function (err, files) {
  if (err) {
    console.log('Error finding files: ' + err)
  } else {
    files.forEach(function (filename, fileIndex) {
      gm(source + filename).size(function (err, values) {
        if (err) {
          console.log('Error identifying file size: ' + err)
        } else {
          console.log(filename + ' : ' + values)
          aspect = (values.width / values.height)
          widths.forEach(function (width, widthIndex) {
            height = Math.round(width / aspect)
            console.log('resizing ' + filename + 'to ' + height + 'x' + height)
            this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
              if (err) console.log('Error writing file: ' + err)

You see the horrible indentation of }) due to code bricks inside other bricks. This is called the Callback Hell.

People writing code like this are doing so because they are used to write code that executes from top to bottom, like any typical programming languages. This is a mistake in javascript because it doesn't execute in the same way as those other languages.

Javascript Callbacks

In any language, when you use a function, you expect to get the result as the output. Like in PHP you would do $number = rand(1, 10); and then you can use the $number variable on the next line.

In Javascript, most function doesn't directly return the result, because it takes some time to execute and to calculate the output.

That is why you often get undefined if you log the result of a function.

var travelResult = goToMars(spaceShip)
// travelResult is 'undefined'!

In this case the function might take a long time to execute your complex script. And you don't want your program to pause until it's done.

Instead, you use a callback to execute the code that will use the function's output.

var travelResult = goToMars(spaceShip, handleArrival)

function handleArrival (error, result) {
  if (error) console.error('Spaceship Exploded !', error)
  else console.log('You are arrived !', result)

console.log('Travel to Mars Started')

There's a good chance that you think this code is weird because the order of the code doesn't look right. In any other programming language, the code would be written in a "correct" order. This is why many people have troubles understanding callbacks in javascript.

How do we fix that ?

There are three rules we can use to make the code cleaner.

  1. Don't use anonymous functions. Instead, give your callback functions a name and then define them at the bottom of your script file.
  2. Make modules and assemble them together. In other words, externalize your functions in separate modules that you import in your project.
  3. Handle every single error in every one of your callbacks
  4. Create reusable functions and place them in a module to reduce the cognitive load required to understand your code. Splitting your code into small pieces like this also helps you handle errors, write tests, forces you to create a stable and documented public API for your code, and helps with refactoring.

In summary, you need to work on advanced refactoring !

You can find more details on the super callbackhell.com


2021 My Dynamic Production SPRL All rights Reserved.