Making a Promise Chain

Promises, promises. Nowadays it’s all the rage in JavaScript, but I found myself late to the game because I spent almost five years at a place that still had to support Internet Explorer 8, the abacus and chalk drawings on cave walls. When everybody around me started talking about “returning a promise”, it was hard for me to avoid being skeptical. I mean, people make promises all the time, right?

I know you tore up my pardon, Womack.

But now I’m working at a much better place and I’m not chained to a giant pile of legacy spaghetti. I can now do things that other people have been doing for a couple of years, and I’m really excited about it. There are no jQuery Deferred objects this time. We’re going to make some honest-to-goodness promises, and we’re going to chain them together.

What’s the Chain For?

The most common use for a promise is to make your code wait until the back-end responds to an AJAX call. You might even have several AJAX calls that have to return before you can do your stuff. It’s a jungle out there, folks. Legacy code threatens us all.

I have an example set up in a fiddle, but I used a Mozilla page on promises to wrap my head around chaining. I’m going to add some snippets from the fiddle and explain them. It’s good to share this stuff, and to be honest it allows me to come back here and use this page as a reference when I forget everything.

let myText = document.getElementById('my-text');
let arrResults = [];

function doSomething() {
  return new Promise( (resolve, reject) => {
    /*
    This Math.random stuff is just being used to simulate
    hitting some kind of API and coming back with
    success or failure.
    */
    if (Math.random() > .5) {
      resolve("SUCCESS")
    } else {
      reject("FAILURE")
    }
  });
}

First I initialized an empty array that I’m going to toss crap into, and then I set up my promise. It’s a function that returns a promise, which has all sorts of magical properties. The main things that you can do with a promise is resolve or reject them. In this case, we’re pretending that we’re sending a call to the worst server in the world, which fails half the time. If it comes back large, it resolves and returns some data. In this case, the data is the string “SUCCESS”. If we get a low result, then we reject the promise. In real life we would get some kind of server response and we could use that to make our decisions.

A good real-world example of using a chain would be to get some data from the server and then use that as part of another request for the server. Maybe you look up a client record and then use something in the client’s data to ask for some other thing. Obviously you can’t make that second call until the first one comes back successfully.

So when we call doSomething() we’ll end up with a string that’s either “SUCCESS” or “FAILURE”. In real life these would be JSON objects with stuff in them, but this is just a simple example so we’re using strings. If the call works out, we run another funtion. If not, we just stop and run the catch function. Here’s the code for that.

doSomething()
  .then( result => {
    //console.log('1st Success callback: ', result);
    arrResults.push(result);
    return result;
  })
  .then( result => {
    //console.log('2nd Success callback: ', result);
    arrResults.push('Second Thing');
    return result;
  })
  .catch( result => {
    //console.log('*** Failure callback: ', result);
    arrResults = [result];
    return result;
  })
  .finally( result => {
    //console.log('*** Finally callback: ', result);
    myText.innerHTML = arrResults.join(', ');
    return result;
  });

First we run doSomething() which returns a promise that has cool methods on it. To see them, run a function like this in the console and just take a look at what comes back. Anyway, the result of the promise is included as an argument. Remember when we resolved things with “SUCCESS” as an argument? Well, here’s where it comes out of the pipe. After that, the then() kicks in, returning a brand-new promise. Remember that, every one of the links in this chain returns its own promise. That allows all of them to run in sequence, with nobody jumping ahead.

We could do just about anything with our first then(), but we’re just going to push a value to that array that we prepared earlier. Now we have an array with two things in it, and we immediately write all of it to a DOM node that we grabbed in the first line of our example. So you end up with a paragraph tag that contains “SUCCESS, Second Thing”.

If our fake server barfs, then the whole thing is skipped and none of our precious chain links will run. We wind up in the catch() method with our data, which in this case is just the string “FAILURE”. We’re sad and we have no data, so we just stuff our failure into the paragraph tag and try to move on with our lives.

After everything is over one way or another, we run the finally() method on our promise chain. This method runs no matter what, so it’s a good place to put our join statement and toss whatever results we have into our paragraph tag. This allows us to run those lines once and keep our code as DRY as we can. So even if we fail, at least one method is going to be reasonably happy.

Ben Affleck and Henry Cavill discuss BvS

The Catch and Finally methods discuss the results of our AJAX call.

So this is a basic example of a promise chain. The idea is to have things arranged in a nice, readable format instead of having the crazy nesting vortex that we used to write with jQuery. This isn’t intended as a deep dive into promises, but I hope this can serve as a reference for how this stuff can be put together. I know I’ll need it later, especially if I’m coding without coffee.