ES6 Javascript 中使用 Generator 取消 Promise 简介

2025-06-07

使用 ES6 Javascript 中的生成器取消承诺

介绍

在我之前的博客文章中,我解释了 ES6 JavaScript 中生成器的基础知识。如果你还没读过,可以在这里查看👉理解 ES6 JavaScript 中的生成器

你们中的许多人都要求提供生成器的实际用例,因此我将展示我遇到的一个问题。

介绍

但为了解释这个问题,我必须简单介绍一下我们正在开发的产品Mews Navigator 。

Navigator 允许您在线办理登机手续,安全地存储您的信用卡详细信息,并让您完全控制您想要共享的信息。

现在,想象一下您正在通过应用程序进行在线登记,并且正在进行付款步骤。

因此,一旦您单击“下一步”按钮,您就会看到一个加载器,然后是您的支付卡列表,非常简单,对吗?

网上值机中的 Navigator 付款步骤

呈现支付路线

实际上,底层机制要复杂得多。在组件渲染之前,需要解决几个步骤。

// 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
Enter fullscreen mode Exit fullscreen mode

在渲染组件之前,我们进行了一些检查并获取了一些 API。

问题是,如果任何一项检查失败,并且根据失败的检查,我们将重定向到特定的案例。

那么如何在不使用任何外部库的情况下解决这个问题呢?还记得上次我给你展示的这个例子吗?

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();
Enter fullscreen mode Exit fullscreen mode

在 codesandbox 中查看源代码

看一下该return语句。这将停止执行并忽略该return语句之后的所有内容。

这使我们能够迭代承诺并在承诺链中的任何地方取消。

概念验证

让我们创建一个足够通用的方案,以便在路由中解决这个问题。要点如下:

  • 能够处理同步和异步函数(API 调用)
  • 一旦某些检查失败,代码就会返回重定向。
  • 足够通用,因此我们也可以将其重新用于其他路线。

所以我打开了代码沙盒并想出了这个解决方案👉Codesandbox

正如您在控制台中看到的,我们有多个操作和一些检查。我们可以绕过那些应该失败的检查,这样其余代码就不会执行。

网上值机中的 Navigator 付款步骤

在 codesandbox 查看源代码

下面是代码中支付步骤路线的实现示例。

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 />)
  )
};
Enter fullscreen mode Exit fullscreen mode

我必须为我们的生成器编写一个处理程序。这就是事情发生的地方magic。我已经在下面的评论中解释了每个步骤。

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());
};
Enter fullscreen mode Exit fullscreen mode

在 codesandbox 查看源代码

目前,我只是在玩它,所以如果你知道如何以更好的方式解决这个问题,一定要告诉我。😉


感谢阅读

请在评论区告诉我你对这个生成器系列的感受。如果你喜欢它,你就知道该怎么做了!和你的朋友和同事分享吧。

如果您希望我在下一篇文章中讨论一些主题,请在dev.to或 twitter @phung_cz上给我发私信,或者如果您有任何建议,请随时在下面发表评论。

下次再见,继续黑客攻击✌


看看我们在 Mews 系统上正在开发什么,我们也在招聘开发人员和其他职位的人员。如有任何疑问,请直接联系我。

文章来源:https://dev.to/tuanphungcz/canceling-promises-with-generators-in-es6-javascript-d01
PREV
理解 ES6 JavaScript 中的生成器
NEXT
使用 Gatsby 和 Strapi 构建网站 - 简介