Before I jump into that seemingly strange analogy, let me do a quick recap on promises. Before we had promises, we handled asynchronous calls using callback functions. Asynchronous, or "async," is just a fancy way of saying, “Hey, this response you want is gonna take a minute, so come back later.”
These types of functions are usually used when we are working with APIs. Asynchronous calls return a result, like all functions, but they take a little longer to produce the result. These callback functions would get nested in other callback functions. When the first function was done running, it would run the second function and on and on down the line. This resulted in what we called "callback hell," like so:
Now, back to that Chipotle analogy. imagine you walk into Chipotle, and you walk up to the first person behind the counter and you order a burrito. The first person behind the counter grabs a tortilla, warms it up and then passes it to the next person in the assembly line. That second person adds beans and rice and passes that onto the next person in the assembly line. The third person adds meat and toppings before wrapping everything up and handing it to the cashier. The cashier rings it up and gives you your burrito, with all the delicious fillings you ordered. This is kind of how a promise chain works.
A promise is an object that can be in a "one-of-three" state, meaning that it can be pending, fulfilled or rejected. If it’s pending, we are just letting the Chipotle worker do their thing while they are getting our order together. Once you ordered a burrito, the first worker will fetch a tortilla, warm it up and once they are done, their job changes from pending to fulfilled, because they have successfully resolved your request. Alternately, the worker might turn to you and reject your request for a burrito because they didn’t hear you or they are sold out of tortillas — a sad day for sure.
Once we have gotten our response back, we chain on a ‘.then( )’ function to give instructions of what to do next. The ‘.then’ function expects to receive a function (or set of instructions) to be executed when the promise has been fulfilled. We also will usually add a ‘.catch’ function to the promise chain to be executed if and when a promise has been rejected.
One thing to remember is that as we go down the chain, we need to make sure that we use the return keyword down the line so the next ‘.then()’ function has access to it. If we don’t return anything, it’s basically as if the first Chipotlle burrito fetches our tortilla, hands it to the next person in line. This second person adds some beans and then throws your burrito on the floor and nothing gets passed down to the next guy. How sad!
With ES8, we got some syntactic sugar called ‘async/ await’ to clean up our Promises. "Syntax sugar" means that we didn’t get any new functionality, but we got a shorter, nicer-looking way to write asynchronous functions. Below is an example of how we would implement async/await on our previous burrito building function:
The code inside the async function is put on pause with await. The await functions wait until the function/’promise’ is successful or rejected and then move down the line. An important thing to remember is that ‘await’ can only be used inside of an async function block.
There is more detail that we could go into about async/await, like how we handle errors, but this is a good starting point. It’s kind of like the promise chain we saw previously, but with cleaner syntax that is more readable and easier to debug.
Promises can be a tricky concept to wrap your head around. Hopefully, this article not only made you hungry for burritos, but you understand how we solved the problem of callback hell with the implementation of Promises. In order to understand async/await, we have to understand Promises and how they function. And in order to understand the flow of Promises, you should always think of the friendly workers at Chipotle building you a tasty burrito… and may they never be out of tortillas or throwing your burrito on the floor.
This post was written by Aylin DeBruyne, Developer in Residence.