If you have ever gambled or watched a movie about gambling, then you can understand promises in JavaScript.

We all love the asynchronous capabilities of JavaScript. In fact, we love them so much that sometimes, we overindulge. And then we get code that looks like this “pyramid of doom”.

Image Credit

This is commonly known as “callback hell” because you probably don’t want to re-read that code and try to understand how everything works, and in what sequence it works. In fact, nobody on your team does either.

A few things are difficult about the above example:

  • Unclear error handling. What happens if something goes wrong?
  • Each function depends on the previous function. You do not need the asynchronous style. You want to make the order clear to others reading the code. When you chain this many functions together, a synchronous style of code will be more readable.
  • You need to continually track the variables for input into a function, and then output. And also track the logic that happens to each output. This becomes exhausting.

You could make this entire process more understandable using promises. If you are like me, you may have heard of promises once or twice, but then ignored them because they seemed confusing. The basic uses of promises are actually pretty easy if you understand callbacks.

Promises encourage straightforward, single-purpose functions that will allow you to write clear code and understand every step without headaches. After thinking about it for a while, I realized that promises are just like a trip to the casino. While a casino “modifies” the amount of money in your bank account (ahem, removes), a chain of promises modifies data in a specific sequence.

So, let’s jump into it. If you do not have experience with callbacks, check out my explanation on the principles of callbacks. If you are looking for a more technical explanation of promises, check out this guide or this guide or this video.

What is a promise?

Let’s say that you are taking a weekend vacation to a casino. You have two weeks of salary in your pocket, and you are going to enjoy every moment as you bet it away, down to the last dime. Or perhaps you will get lucky, and end up winning money?

You get to your hotel room, then head down to the casino. Each type of game accepts cash, so you will need to go to the ATM to withdraw $1000 and get started.

Let’s take a step back and think about this scenario. Although cash can be used for anything outside of the casino, it means one thing inside- the number of games you have left before you run out of money. That cash amount will likely shrink further and further over the course of the weekend. It could also grow, but you have already promised yourself that you will not lose more than $1000 this weekend.


A promise holds the place of a value that does not yet exist, but will certainly exist in the future. This allows you to clearly follow a function and understand its beginning and end. As shown above, promises are a great way of giving clarity to consecutive asynchronous functions and clarifying inputs and outputs.

Here is the above example, in an extensible way:





Doubling down on these examples

If you understand promises at this point, I am freaking amazed! Let’s dig deeper into the first example to break it down line-by-line.

Line 3: You convert your $1,000 in cash into tokens using the getCasinoTokens() function, not pictured here.

Line 4: The .then() statement signifies that the next code block will use the results of the getCasinoTokens() function. Those results will be passed in via the tokens argument. This segment, lined 4–6, is now an unfulfilled promise. We took in the tokens value, and we are waiting to transform that value before we can move on. A return statement will fulfill it.

Line 5: We call the playBlackjack() function with 30% of the tokens. Since blackjack can only be played with tokens, it is important that this argument is in the form of a number. If it was a string, or array, or object, this function would throw an error, and we would reject the promise. When the promise is rejected, we move down to the .catch() function on line 13 to see what to do if an error occurs. Fortunately, tokens is a number, the function finishes, and this promise is fulfilled. We input one token amount, did some betting, and came out with a new token amount

Line 7: There is another .then() function, which means we now have another unfulfilled promise. The input value for this promise is the result of the return statement from the previous function. In this case, it is a token count after playing blackjack. This is fed into the promise via the moreTokens argument. If you were at the casino, you would have taken your resulting pile of tokens and moved directly to the next game, roulette.

Line 8: If the playRoulette() function is successfully completed, this promise will be fulfilled. In this case, as long as moreTokens is a number, it will complete successfully. And then we repeat this process for every consecutive .then() function.

Line 13: The catch() function handles any errors, so we do not need to do error handling within every single function or neglect error handling entirely.

The key to promises is the concept of unfulfilled, fulfilled or rejected. Once you create a sequence of these promises, you have a clear flow of inputs and outputs, and clear code for others to read. You can use the 3 different states to track the progress of the entire chain of promises. The style is synchronous (sequential), even though the actual execution is asynchronous.

Get The Latest Tutorials

Did you enjoy this explanation? Sign up here to get the latest visualized tutorials of HTML, CSS and JavaScript.