Canceling promises with Generators in ES6 Javascript
Tags: javascript, generators, async, promise
Published: 2019-05-20 10:48:18

---
title: Canceling promises with Generators in ES6 Javascript
published: true
description: Many of you asked for the real life example of generators, so here it goes!
tags: #javascript #generators #async #promise
cover_image: https://i.imgur.com/6FoNqoP.png
series: Generators in ES6 Javascript
---

In my previous blog post about I explained the basics about generators in ES6 Javascript. If you haven't read you can check it out here 👉[Understanding generators in ES6 Javacsript](https://dev.to/phung_cz/understanding-generators-in-es6-javascript-7fm)

Many of you asked for a real-life use case of generators so I'm going to show one of the problems that I have encountered.

# Introduction

But in order to explain the problem I have to tell a few words about our product **Mews Navigator** that we're working on.

> The Navigator allows you to check-in online, securely storing your credit card details and giving you full control over the information that you want to share.

So now, imagine that you are doing the online check-in via the app and you are proceeding to the payment step.

So once you click on the next button, you would see a loader and then a list of your payment cards, quite straight forward, right?

![Navigator payment step in online check-in](https://s3.gifyu.com/images/May-17-2019-00-31-08.gif)

## Rendering the payment route

Actually, it's a bit more complex under the hood. There are a few steps that need to be resolved before the component is rendered.

```javascript
// Let's say user goes to this url:
// www.mews.li/navigator/check-in/payment/:reservationId

// 1. This will check if the user is signed in.
// If yes go render <Dashboard /> if not go to <SignIn />
authAction(); // async

// 2. We need to fetch the reservations
fetchReservations(); // async

// 3. We need to check if `reservationId` and
// route itself is valid (If all checks pass go to next one)
isReservationIdValid({ reservations, currentReservation }); // sync

// 4. Fetch paymentcards
fetchPaymentCards(); // async

// 5. Fetching hotel entitites
fetchHotels(); // async

// 6. Some of hotels uses PCI proxy vault, if it does,
// we need to initialize PCI proxy script.
doesHotelUsePciProxy({ hotels, hotelId }); // sync

// 7. Fetch and init the script
initPciProxy(); // async
```

We have a few checks and some APIs fetching before rendering the component.

> The catch is that if any of these checks could fail and based on which checks to fail, we would redirect to a specific case.

So how to solve this without using any external libraries? Remember last time, when I showed you this [example](https://dev.to/phung_cz/understanding-generators-in-es6-javascript-7fm)?

```javascript
function* avengersGenerator() {
  yield "Hulk"; // Pausing the execution
  yield "Thor";
  yield "Iron man";
  return "Ultron"; // Exiting of finishing the generator
  yield "Spiderman";
}

const iterator = avengersGenerator();

iterator.next();
```
[View source code in codesandbox](https://codesandbox.io/s/7jkr9y3o81)

Have a look at the `return` statement. This would stop the execution and ignore everything that is after the `return` statement.

This could give us the possibility to iterate over promises and cancel anywhere in a promise chain.

## Proof of concept

Let's create something that is general enough for our use case to solve this case in the routing. The main points were:

- Able to deal with sync and async functions (API calls)
- The code returned redirect as soon as some of the checks fail.
- General enough so we can reuse for other routes as well.

So I opened code sandbox and I come up with this solution 👉 [Codesandbox](https://codesandbox.io/s/understanding-generators-8oe8q)

As you can see in the console, we have multiple actions and some checks. *We can move around the check that is supposed to fail and the rest of the code is not executing.*

![Navigator payment step in online check-in](https://s3.gifyu.com/images/generator-example.gif)
[View the source code in codesandbox](https://codesandbox.io/s/understanding-generators-8oe8q)

And here is the example of implementation for the payment step route in the code.

```javascript
function* paymentRouteGenerator() {
  yield authAction();
  yield fetchReservations();
  yield isReservationIdValid();

  yield fetchPaymentCards();
  yield fetchHotels();
  yield doesHotelUsePciProxy({ hotelId });
  yield initPciProxy();
}

const CHECK_IN_PAYMENT_ROUTE = {
  name: Route.CheckInPayment,
  path: "/:reservationId",
  action: resolveAction(
    generatorWrapper(paymentRouteGenerator),
    renderComponent(() => <CheckInPaymentStep />)
  )
};
```

I had to write a handler for our generator. This is a place where the `magic` happens. I have explained every step below in the comments.

```javascript
const generatorWrapper = generator => context => {
  // 1. Creating an iterator
  const iterator = generator(context);

  // 3. This function except yielded as a argument
  const handle = yielded => {
    const handleWithRedirectCheck = route => {
      // 4. Here is where the magic happens, we check if there is a redirect, if yes,
      // it would redirect (cancel) and will not execute the rest of the generator
      if (get("redirect", route)) {
        return route;
      }
      // Otherwise continue
      return handle(iterator.next());
    };
    // Exit if we are at the end of the generator
    if (yielded.done) {
      return;
    }

    // Handling the async case if action/check is a promise
    if (isPromise(yielded.value)) {
      return yielded.value.then(handleWithRedirectCheck);
    }
    // If its not a promise, we can call handleWithRedirectCheck directly
    return handleWithRedirectCheck(yielded.value);
  };

  // 2. Handling the iterator
  return handle(iterator.next());
};
```

[View the source code in codesandbox](https://codesandbox.io/s/understanding-generators-8oe8q)

For now, I'm just playing with it, so if you have any idea how to solve this in a nicer way, definitely let me know. 😉

---

## Thanks for reading

Let me know in the comments section how you feel about this **generators series**. If you love it, you know what to do! Share it with your friends and colleagues.

If you want me to cover some topics in the next post, DM me on here on [dev.to](https://dev.to/phung_cz) or on twitter [@phung_cz](https://twitter.com/phung_cz), or if you have any suggestions, feel free to comment below.

See ya next time and keep on hacking ✌

---

*Have a look on what are we building [@ Mews systems](https://github.com/MewsSystems/developers) we are also [hiring devs](https://github.com/MewsSystems/developers) and people for other positions. DM me if you have any questions.*