您的位置:首页 > 其它

中断或取消 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();


其实还能
break
ThenFail
each
helper:
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;
});


另外, 释放上下文也会释放嵌套的上下文.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: