使用 ES6 Javascript 中的生成器取消承诺
介绍
在我之前的博客文章中,我解释了 ES6 JavaScript 中生成器的基础知识。如果你还没读过,可以在这里查看👉理解 ES6 JavaScript 中的生成器
你们中的许多人都要求提供生成器的实际用例,因此我将展示我遇到的一个问题。
介绍
但为了解释这个问题,我必须简单介绍一下我们正在开发的产品Mews 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
在渲染组件之前,我们进行了一些检查并获取了一些 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();
看一下该return
语句。这将停止执行并忽略该return
语句之后的所有内容。
这使我们能够迭代承诺并在承诺链中的任何地方取消。
概念验证
让我们创建一个足够通用的方案,以便在路由中解决这个问题。要点如下:
- 能够处理同步和异步函数(API 调用)
- 一旦某些检查失败,代码就会返回重定向。
- 足够通用,因此我们也可以将其重新用于其他路线。
所以我打开了代码沙盒并想出了这个解决方案👉Codesandbox
正如您在控制台中看到的,我们有多个操作和一些检查。我们可以绕过那些应该失败的检查,这样其余代码就不会执行。
在 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 />)
)
};
我必须为我们的生成器编写一个处理程序。这就是事情发生的地方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());
};
目前,我只是在玩它,所以如果你知道如何以更好的方式解决这个问题,一定要告诉我。😉
感谢阅读
请在评论区告诉我你对这个生成器系列的感受。如果你喜欢它,你就知道该怎么做了!和你的朋友和同事分享吧。
如果您希望我在下一篇文章中讨论一些主题,请在dev.to或 twitter @phung_cz上给我发私信,或者如果您有任何建议,请随时在下面发表评论。
下次再见,继续黑客攻击✌
看看我们在 Mews 系统上正在开发什么,我们也在招聘开发人员和其他职位的人员。如有任何疑问,请直接联系我。
文章来源:https://dev.to/tuanphungcz/canceling-promises-with-generators-in-es6-javascript-d01