Promises in Javascript are a good way to deal with callback hell. Callback hell is a situation you may find yourself in while writing javascript, having to deal with it’s asyncronous nature which can sometimes be tricky.

If you don’t know what callback hell is, I’ll give you an example. Lets say you have a program that first fetches data from some api ( which can take X amount of time ), then it passes the returned data to another function to manipulate the data ( which can take Y amount of time ), and then with that data we have to fetch more data using the newly manipulated data…

somefile.js


// assume get is some library like jQuery or fetch (although these already have Promise features built in...)

var reqData1 = function(userId, callback) {
  get('www.someFakeApi.com/users/' + userId, function(err, response) {
    // when calling the function, the callback arg will actually be a
    // function, called with the args (err, dataIfSuccessful)
    if (!response) callback(err, null)
    callback(null, response.data)
  })
}

var manipulateData = function(data, callback) {
  // ...
  // MANIPULATE THE DATA PASSED IN AS AN ARG SOMEHOW...
  // ...
  callback(null, newlyManipulatedData)
}

var reqData2 = function(someData, callback) {
  get('www.anotherFakeApi.com/something/' + someData.something, function(err, response) {
    if (!response) callback(err, null)
    callback(null, response.data)
  })
}

so here we just have 3 functions that all have a callback to be called once it’s done doing what it needed to do. Heres what calling these functions would look like:

somefilept2.js


reqData1('a12das2', function(err, data) {
  manipulateData(data, function(err, modifiedData) {
    reqData2(modifiedData, function(err, data) {
      // run this code once all processes are done!
    })
  })
})

In large programs where there can be many callbacks you need to call by chaining them together, you can see how this can become tedious. Promises offer a nice way to deal with this problem.

built in Promise object

There are many good promise libraries, such as Q (https://github.com/kriskowal/q) & bluebird (https://github.com/petkaantonov/bluebird). Instead of using an external library, there is actually a Promise object that was implemented in ecmascript 2015 that we are going to use instead.

Here is a blueprint for how you can construct a promise in Javascript:

somefile.js


function doSomething(userId) {
  return new Promise(function(resolve, reject) {
    // ... do some async code here, maybe request data from some api's
    if (someError) reject(userId)

    if (someSuccess) resolve(userId)
  })
}

// calling the promise

doSomething('asdadadz')
  .then(function(successData) {
    // where successData is from resolve(userId)
    // ... do some other actions
  })
  .catch(function(failError) {
    // where failError is from reject(userId)
    // ... do some other actions
  })

Whenever a Promise object is instantiated, 2 methods become availible to chain onto the end of the function call, .then() & .catch(), to help us decide what to do after the execution of an asyncronous task. So .then() is to be called when the Promise function reaches resolve(xxx), and .catch() is to be called if/when the Promise function reaches reject(yyy).

With that being said, the Promise can be in 1 of 3 states at a given time:

  • PENDING : the promise outcome hasn’t been determined yet
  • FULFILLED : the async operation has finished & has a value
  • REJECTED : the async operation has failed & will never be fulfilled

What is also really nice is that we can chain X amount of .then()’s onto each other, where the argument of the trailing .then() is what is ‘return’d from the previous .then()

somefile.js


doSomething('asdadadz')
  .then(function(successData) {
    // where successData is from resolve(userId)
    // ... do some other actions ...
    return 2 + successData
  })
  .then(function(newSuccessData) {
    // ... manipulate newSuccessData even further ...
    return something
  })
  .then(function(something) {
    // ...
  })
  .catch(function(failError) {
    // where failError is from reject(userId)
    // ... do some other actions
  })

This can be a very effective way to deal with Javascript sometimes tricky asyncronous nature.