News & Views

Getting Started with JavaScript Promises: Part 1

Why Do We Need Promises?

If you've done much with JavaScript you've definitely had a run in with it being asynchronous, or "async." What does that mean? Basically, it doesn't necessarily run every line in the order (top to bottom, left to right). It usually does, but sometimes things happen that it has to wait for and JavaScript doesn't wait. Ever. This is what makes a lot of back-end programmers frustrated with JavaScript, but it is actually one of the strongest assets it has.

JavaScript will run whatever line can be run RIGHT NOW, next, from top to bottom. This means that when you have an operation that takes a little time, getting the weather from an API or making a database query for instance, it's going to skip the code that is supposed to be run when that's done and come back later (that's the "out of order" part). Traditionally, the answer to this is to put your callbacks inside of callbacks, inside of callbacks. That ultimately makes it look like this:

It's happened to me many times. No thanks. Promises are the answer.

How Do Promises Work?

Here's an example. Imagine it's a beautiful sunny Saturday and you have a few errands to run. You make a list before you leave your house at 9 a.m.:

  1. Call customer service and straighten out phone bill (on hold, + talk = 20 min)
  2. Get groceries (store opens at 10)
  3. Take car in for oil change (30 min drive + 10 min service)

If you start with the first one, you are going to sit at home on hold for 15-20 min doing nothing but waiting. How inefficient. You can't do the second one yet because the store won't open for another hour. However, you have Bluetooth in your car, so you can hop in, head to the service station AND can get the call started. By the time you get to the oil change location, you will have completed your phone call -- knocking out two things at almost the same time.

What's important to remember here is you started 1, then 3, finished 1, finished 3, then started and finished 2. That's async.

The interesting part is what can happen on the phone call or the oil change. It could be that once you've waited your 15-20 minutes, the company may:

  1. Resolve the issue for you
  2. Not be able to help you
  3. You might get disconnected

You need to be able to handle all of these possible outcomes. If you get disconnected, you'll need to call back. If you they can't help you, you may need to do some more research. Hopefully, it gets resolved. That's Promises. When JavaScript runs, it runs top to bottom, left to right. If it gets to something that it has to wait for, an AJAX request for instance, it's going to go ahead to the next possible line. I.e., it will skip everything that can't be done until the process is finished. In our example, that's getting the call started (but not waiting for it to finish), skipping the groceries because it's not time yet, and going on to start the car journey. But a given outcome may change what you do. If the phone company can't help you or you get disconnected, you will need to gather more information or call back. Promises are a built-in way to tell JavaScript what to do for all the possibilities and order things correctly without slowing it down.

How You Can Start Using Promises In JavaScript

Let's start simple. A promise is a constructor, a built-in JavaScript class, that you can create anytime, anywhere in JavaScript. Open up your favorite means of running JavaScript, or head to Replit. Start with just this.

var aPromise = new Promise((resolve, reject) => {})

We are making a variable named "aPromise" and using JavaScript syntax to set up a new object. The Promise object always takes one argument, a callback with a resolve and reject object as its arguments. In simplest terms, JavaScript will see the variable "aPromise" as unfinished until either resolve or reject is called. That is, just like our illustration up above, if we wanted to wait to go to the grocery store until the oil change and the phone bill were figured out, we could WAIT until they are both finished. That's what resolve and reject are for. They let our other tasks know when it's OK to move forward. Let's add something in to test. setTimeout is an easy example because it means JS will wait as long as we need it to.

var aPromise = new Promise((resolve, reject) => {
setTimeout(()=>{
console.log("Done counting!");
}, 2000)
});

If you drop this into Repl, it will wait two seconds after you run it, and then print to the console, "Done Counting." No magic here, right? Let's add something else.

var aPromise = new Promise((resolve, reject) => {
setTimeout(()=>{
console.log("Done counting!");
}, 2000)
});
console.log("You done yet?");

As you can see, they run "out of order" except not really. We started the first task, couldn't finish it, so JS went on to the second task, finished it, then came back to finish the first. Just like our example, things can be done faster this way. But let's say we wanted the second one to wait until the first was done. Now we need the promise. Same code, but we are going to call resolve now.

var aPromise = new Promise((resolve, reject) => {
setTimeout(()=>{
console.log("Done counting!");
resolve();
}, 2000)
});
aPromise.then(()=>{
  
console.log("You done yet?");

});

The "then" method is the magic of promises. It gives JavaScript a way of keeping an eye on the promise and WILL ONLY RUN when resolve is called inside the promise. However long that takes, JS will patiently wait until it's finished before it runs the subsequent code.

Stay tuned for the next Promises blog where we'll cover the catch and all methods!

Interested in learning more about JavaScript? It's just one of the many programming languages and frameworks we cover in our programs. Click the button below to download a course packet to find out more about our curriculum!

Download Catalog
Rob Bunch Rob Bunch Immersive Web Instructor, Atlanta LinkedIn