中断或取消 Promise 链
2016-04-12 22:16
337 查看
Promise
Promise 已经成为了 JavaScript 管理异步操作的重要工具之一. 然而, 有的时候还是会很头痛:Promise // 等价于 `Promise.resolve(undefined).then`. .then(() => { // 开始. }) .then(() => { if (wantToBreakHere) { // 怎样在这里终止这个 Promise 链? } }) .then(() => { // 一定条件下不想被执行的代码. });
当然我们可以嵌套后面的
then, 但如果整条链很长很厚,
也必然很痛苦.
不过很多 Promise 实现都有一个
catch方法,
我们可以做一点点小动作:
/** 用于中断的信号 */ class BreakSignal { } Promise .then(() => { // 开始. }) .then(() => { if (wantToBreakHere) { // 抛出中断信号. throw new BreakSignal(); } }) .then(() => { // 需要跳过的部分. }) // 接住中断信号. .catch(BreakSignal, () => { });
其实个人觉得这么干还是比较优雅的, 但如果中间还有其他的 onrejected handler, 则需要手动传递
BreakSignal(再次抛出).
现在考虑另一种不同于
break的情形:
page.on('load', () => { Promise .then(() => asyncMethodA()) .then(result => asyncMethodB(result)) .then(result => { // 更新一些东西... }); });
如果
load事件在短时间内触发了两次,
我们则需要取消前一个 Promise 链, 或者至少要防止它执行完成后做一些不该做的事情 (比如更新数据或者 UI).
那我们可以考虑这么处理:
class BreakSignal { } let context; /** 创建包含上下文信息的 wrapper */ function createWrapper() { let currentContext = context; return function (handler) { return function () { if (context !== currentContext) { throw new BreakSignal(); } return handler.apply(undefined, arguments); }; }; } page.on('unload', () => { context = undefined; }); page.on('load', () => { context = {}; let wrap = createWrapper(); Promise // 包起来~ .then(wrap(asyncMethodA)) .then(wrap(asyncMethodB)) .then(result => { // 更新一些东西... }) .catch(BreakSignal, () => { }); });
[AD] ThenFail
因为平时用的是自己的 Promise 实现 - ThenFail - 所以自己有需求一定要满足自己. 我愉快地添加了伪 break语句.
import { Promise } from 'thenfail'; Promise .then(() => { // 开始. }) .then(() => { if (wantToBreakHere) { // 就是这么任性. Promise.break; } return Promise .then(() => { Promise.break; }) .then(() => { // 这里永远也不会执行. }); // 嵌套的情况不需要最下面的 `enclose()`. }) .then(() => { // 需要跳过的部分. }) // 结束当前的 Promise 链的上下文 (context), 避免 `break` 掉太多. // 如果这个 Promise 链会被返回, 交给不在你控制范围内的代码, 那么 enclose 操作非常重要~ .enclose();
其实还能
breakThenFail
的
eachhelper:
Promise .each([1, 2, 3], value => { if (value > 1) { Promise.break; // 或者异步地 `break`: return Promise .then(() => { // 做一些事情. }) .break; } }) .then(completed => { if (completed) { // 一些代码... } });
当然有的同学可能看出来了,
Promise.break这个伪语句实际上是一个会抛出异常的
getter, 抛出的异常则是类似于
BreakSignal的这么个东西
(虽然实现上一个是
object1 === object2,
一个是
object instanceof Class).
前面有提到 ThenFail 中上下文的概念, 如果需要取消相同上下文的整个 Promise 链, 只需要释放对应的
context即可.
let context; page.on('unload', () => { context.dispose(); }); page.on('load', () => { let promise = Promise .then(() => asyncMethodA()) .then(result => asyncMethodB(result)) .then(result => { // 更新一些东西... }); context = promise.context; });
另外, 释放上下文也会释放嵌套的上下文.
相关文章推荐
- 进程和线程关系
- 关于python中字典的一些总结
- 学习进度06
- 计算数值的整数次幂
- 龙书D3D11章节习题答案(第五章)
- codeproject网页翻译
- 硬件知识
- MFC改变编辑框默认显示内容
- 采购管理、信息与配置管理
- linux下编译ffmpeg
- sizeof()的用法和注意事项
- 浅谈设置JVM内存分配的几个妙招
- dubbo学习过程、使用经验分享及实现原理简单介绍,dubbo经验分享
- TypeScript笔记
- Java Applet如何正常运行
- POJ-3279 经典翻转问题
- 硬件知识
- ASP.NET 应用生命周期19个事件简介
- activity入门
- Linux上使用Qt Creator进行C/C++开发