DEV Community

Cover image for Promises, Promises...
Meike
Meike

Posted on • Edited on

Promises, Promises...

Ah! Promises! Who doesn't know the joys and disappointments that come with these future oriented constructs - no matter if we are talking about JavaScript promises or their human verbal counterparts! In the end, that's the whole point, right? They don't just arbitrarily share a name, but also behave pretty much the same. Here's an example:

Suppose as a child we wanted nothing more badly than a gaming console. Our father promises to fulfill us our wish and get us a console for our birthday. Once stated, the outcome of this promise is still pending though - if our father is a man of his word and we will indeed hold the object of desire in our hands once our birthday comes around, the promise has been fulfilled. Should he (maybe under the never to be underestimated influence of the mother) change his mind however, the promise will be rejected.
In JavaScript, promises are also always in one of these three states: either pending, fulfilled, or rejected. If we were to translate the example from above into code, it could look something like this:

let isDadInfluencedByMum = false

let willIGetTheConsole = new Promise((resolve, reject) => {
  if(!isDadInfluencedByMum){
    const gameConsole = {
      brand: 'xbox',
      color: 'black'
    }
    resolve(gameConsole); // fulfilled
  }
  else{
    let reason = new Error('Oh no... Mum had a word with dad!')
    reject(reason) // rejected
  }
})
Enter fullscreen mode Exit fullscreen mode

Should the father stay uninfluenced by the worries of the mother regarding the acquisition of a gaming console, the promise will be kept and the resolve() method of the Promise object is called. The method sets the state of the Promise as fulfilled with the value of the argument it is given - in this case the gameConsole object. However, should the mother happen to have a word with the father before our birthday, it could happen that her influence will convince him to reject the idea of a gaming console after all and therefore the promise. In that case the reject() method with the reason for the rejection is called.

Now, once our birthday rolls around and we finally get to open the presents, one out of two scenarios could happen: either the promise of the father has been fulfilled and we find a new black Xbox in our possession, or we have to realise once again that mothers always have the final say...

const openPresent = () => {
  willIGetTheConsole
    .then((fulfilled) => {
      console.log(fulfilled) // output: {brand: 'xbox', color: 'black}
    })
    .catch((error) => {
      console.log(error.message) // output: 'Oh no... Mum had a word with dad!'
    })
}

openPresent()
Enter fullscreen mode Exit fullscreen mode

The purpose of promises in JavaScript is mainly to provide a more elegant way of handling asynchronous code without having to fall into the dreadful callback hell. For that reason JavaScript promises can be chained, so that we are able to define promises that depend upon another.

Getting back to our example:
After the father has promised us to fulfill our wish, we rush to our friends in order to report the good news. Obviously the excitement and curiosity of the friends is just as big as our own, so we promise them that everyone gets to play with the console at the birthday party. In order to be able to keep this promise though, our father, of course, has to fulfill his one first.
Let's put our promise to the friends into code:

const letEveryonePlay = (gameConsole) => new Promise(
  (resolve) => {
    let invitation = `Hey, let's all play together with my new ${gameConsole.brand}!`
    resolve(invitation);
  }
)
Enter fullscreen mode Exit fullscreen mode

Now we're going to chain the two promises together. We can do this by using the then() method. First we have to wait and see if the father has kept his promise and we actually got the gaming console, only then can we fulfill our promise to the friends:

const openPresent = () => {
  willIGetTheConsole
    .then(letEveryonePlay)
    .then((fulfilled) => {
      console.log(fulfilled) // output: "Hey, let's all play together with my new xbox!"
    })
    .catch((error) => {
      console.log(error.message) // output: 'Oh no... Mum had a word with dad!'
    })
}

openPresent()
Enter fullscreen mode Exit fullscreen mode

Once we finally get to rip off the wrapping paper and discover the gaming console we are able to fulfill our promise and invite all of our friends to play with it.
The fulfilled promise of willIGetTheConsole returns the gameConsole object, which we then use in the letEveryonePlay promise to get the brand of the console in order to return a proper formulated invitation message, which we can then print once the promise of letEveryonePlay has been fulfilled.

Should the present contain something else though, the reason why we have to disappoint our friends is likely going to be the same as before - the voice of reason has spoken and the father has caved in.

I hope this little example was able to help one or the other in understanding how to make use of JavaScript's promises. Even if you are not necessarily confronted with the problem of having to wait for an "ok" from your parents to get yourself a gaming console anymore, they are just as suited e.g. to make sure a full set of data is returned before further processing it, or keeping code for unzipping files in check until they have been fully downloaded. Whatever the use case, thanks to their "chainability", promises are definitely a much more readable and elegant solution to a bunch of deeply nested callback functions and once you get your head around how they work, you will not want to miss them.

Promise!

Top comments (0)