Callback Hell

The other day I was working with three asynchronous functions e.g. asyncF1, asyncF2, asyncF3 where each one returns a Promise to the next one. I had a basic understanding of Promises so I started coding and got some code like this

asyncF1()
  .then(function(responseF1) {
    // call asyncF2 with the result from asyncF1
    return asyncF2(responseF1)
      .then(function(responseF2) {
        // and asyncF3 accordingly
        return asyncF3(responseF2)
          .then(function(responseF3) {
            // finally we get to the end of nesting
            console.log(responseF3);
          })
          .catch(function(failedReasonF3) {
            // handle an error from asyncF3
            console.error(failedReasonF3);
          });
      })
      .catch(function(failedReasonF2) {
      // handle an error from asyncF2
        console.error(failedReasonF2);
      });
  })
  .catch(function(failedReasonF1) {
    // handle an error from asyncF1
    console.error(failedReasonF1);
  });

This code shows what they call a “Callback Hell”. Fortunately Promises have techniques allow you to avoid long or, I would say, nesting at all.

Chaining Promises

I think the main Promise magic happens when a result of the

asyncF.then()

becomes a new Promise. This means you can call a chain of .then() methods and pass parameters between them.

  • If you return a simple value, the next Promise is resolved with that value
    asyncF1()
      .then(function() {
        return 'Hello from asyncF1';
      })
      .then(function(response) {
        console.log(response); // 'Hello from asyncF1'
      });
  • If you return a Promise, the next .then() waits for it to be resolved/rejected and is called with the corresponding result
    asyncF1()
      .then(asyncF2)
      .then(function(responseF2) {
        // we get the result from asyncF2
      });

Handling Errors

There can be one or more .then() method calls that do not have an error handler, then the error is passed to the closest .catch()

asyncF1()
  .then(asyncF2)
  .then(asyncF3);
  .catch(function(error) {
    // shared error handler for above Promises
  });

If there is a .catch() inside a chain of .then() calls, the returned value from .catch() is passed to the next .then() not .catch(). So this can be used to set a fallback or a default value

asyncF()
  .catch(function() {
    return 'DEFAULT_VALUE'
  })
  .then(function(response) {
    console.log(response); // 'DEFAULT_VALUE'
  });

That is the basic info you should know while working with Promises chaining. I hope this helps you.

Suggested Reading