Promises on the example of a burger party

Original author: Mariko Kosaka
  • Transfer


This is a translation of an article that Mariko Kosaka wrote as an alternative introduction to JavaScript promises. She made drafts of illustrations in her notebook while reading various articles on promises. If you want to study in more detail, at the end you will find a list of useful links.

Recently, Mariko participated in a discussion of how to use JavaScript to make a feature that would give access to external data (should have been asynchronous). She said: "Well, let's use fetch()... so in the code ... uh ...", and while trying to remember the fetch API, the interlocutor said: "Promise will come back." According to Mariko, her brain fell into a stupor, and she said: “Honestly, I don’t know what you mean ...”

She had to write code based on promises many times, but for some reason the necessary puzzles in her head for some reason did not connect. She realized that she didn’t really “enter” the essence.

I can’t even describe how difficult it is to explain this expression: “Promise will come back”
But this is probably because I do not understand what “Promise” is.
- Mariko Kosaka (@kosamari) January 13, 2017

If you browse through her twitter , you will see that during training she uses visual images, and for this she draws the concepts used in the code in the form of physical metaphors. So she tries to cope with a double level of abstraction (a programming language and English as a second language). Therefore, she had to turn to drawing this time.

Here is a snippet of code that will be used as an example.

// асинхронная операция
function cookBurger (type) { ... }
// обычная операция
function makeMilkshake (type) { ... }
// функция заказа, которая возвращает промис
function order (type) {
  return new Promise(function(resolve, reject) {
    var burger = cookBurger(type)
    burger.ready = function (err, burger) {
      if (err) {
        return reject(Error('Error while cooking'))
      }
      return resolve(burger)
    }
  })
}
order('JakeBurger')
  .then( burger => {
    const milkshake = makeMilkshake('vanila')
    return { burger: burger, shake: milkshake }
  })
  .then( foodItems => {
    console.log('BURGER PARTY !', foodItems)
  })
  .catch( err => {
    console.log(err)
  })

Let's have a burger party


Welcome to Promise Square Park, where JakeShack Burger is located. Her burgers are very popular, but the number of cash registers for placing orders is limited, so the line of customers at the counter is always large. However, there are excellent cooks in the kitchen who can cook several orders at the same time.

If anything, the prototypes were Madison Square Park and ShakeShack in New York. They are very tasty food, and the line is always large.

Promisification of actions


To take orders as quickly as possible, JakeShack uses a signaling system. When the buyer pays for the order, the cashier issues a tray and an alarm device in exchange for a payment.



The tray is a promise from JakeShack to the client that a tasty burger will appear on the tray as soon as it is ready, and the signaling device shows the status of the order. If he is silent, then the order is pending — the kitchen chefs are busy working on your order. When the screen lights up in red and a beep sounds, this will mean that the order is settled (settled) .

A small nuance associated with the state of " assembled". This is not a synonym for "ready." This means that the order was processed in the kitchen and the buyer needs to decide what to do next. You (the buyer) will probably want to pick up the order behind the counter, however it is also possible that you will simply leave. The decision is yours.

Let's take a look at the code. When you call a function order, it “returns a promise” (gives you a tray with a signaling device). The return value (burger) should appear on the tray when the promise is executed and the callback function is called.



Add Promise Handlers


It seems that the signaling device has rung, which means that you need to go to the counter and ask for your order. Further, two scenarios are possible.



  1. The order is ready (promise made). Hurrah! Your order is ready and the cook hands you a fresh, tasty-smelling burger. Promis done!
  2. Order not ready (promise rejected). It seems that cutlets ran out in the kitchen, so the burger promise was not completed. Get Compensation!

Here's how to prepare for both situations.



.then()accepts another function as the second argument, which can also be used as a reject handler. For simplicity, I used here only .catch(). If you want to know more about how both options are handled, read this article: https://developers.google.com/web/fundamentals/getting-started/primers/promises#error_handling .

Promise Chain (Chaining)


Suppose your order was ready, but you decided that for a burger party you still need a milkshake. So, you are in the C-line (a separate line for drinks, really used in ShakeShack for more efficient order management). When you order your cocktail, the cashier gives you another tray and a different signaling device. And since the milkshake is prepared very quickly, the cashier immediately issues it, along with a tray. No need to wait until the signaling device rings (it already does this!).



Now let's see how our code works. A chain of promises is just adding new to the code .then(). The value returned .then()is always a promise. Just remember that everyone.then()returns a tray and a signaling device, and the real return value is passed as an argument to the callback function.



Now you have a burger and a milkshake, you are ready for a BURGER PARTY!

Extra tricks!


Promises have a couple more methods to do cool tricks.

Promise.all()creates a promise, which takes as an argument an array of promises (elements). This promise is performed when all its elements are satisfied. Let's say you ordered 5 different burgers for your friends, but you don’t want to go and pick them up one at a time all 5 times, and then when they are all ready. In this case, a good solution is Promise.all().

Promise.race()look likePromise.all(), but at the same time, the promise is considered fulfilled or rejected as soon as at least one of its elements is executed or rejected. This behavior allows you to emulate a try and grab scheme. If you are incredibly hungry, you can order a burger, a cheeseburger and a hot dog at the same time, but take the first one from the kitchen. But in this case, if, for example, the kitchen is closed or has stopped working for some reason, and the burger’s promise is rejected first, then the whole promise will be rejected.

You can also read about promises:


Also popular now: