promise.timeout 是我之前发的promise工具包 系列 https://cnodejs.org/topic/573b2d64fcf698421d20359d 中的一个
promise.timeout
promise.timeout 给一个 async function 加上超时支持, 就是你原来的返回值是一promise, 加上timeout支持后, 超时了就会以一个 timeout error reject掉 https://github.com/magicdawn/promise.timeout
function test(){
// 20ms 后去 resolve
return new Promise(resolve => {
setTimeout(()=>{ resolve(20) }, 20);
});
}
const ptimeout = require('promise.timeout');
const test10 = ptimeout(test, 10); // test方法, 10ms 超时
// e instanceof ptimeout.TimeoutError
test10().then(function(res){
console.log(res);
}, function(e){
console.error(e)
});
问题
这里其实是这样的
原来 test() 和 超时定时器比谁先跑完, 10ms的超时定时器先跑完. 于是 test10() 的返回值以 ptimeout.TimeoutError 实例 reject 掉 但是这里有个问题, promise 没有取消机制, 原来的 promise 还在跑…
onCancel
function test(onCancel){
// 20ms 后去 resolve
return new Promise(resolve => {
const t = setTimeout(()=>{ resolve(20) }, 20);
onCancel && onCancel(() => {
clearTimeout(t); // 资源清理
});
});
}
const ptimeout = require('promise.timeout');
const test10 = ptimeout(test, 10, true); // test方法, 10ms 超时, 加了一个 cancel = true 参数
// e instanceof ptimeout.TimeoutError
test10().then(function(res){
console.log(res);
}, function(e){
console.error(e)
});
如果给 ptimeout 的第三个参数传 true, 表示打开 cancel 支持, 这样
- test10 在 调用 test 的时候, 会多传一个 onCancel 参数
- test 可以拿 onCancel 注册回调, 在超时器先跑完的情况下, 可以去清理你这个 promise 所占有的资源
- 然后在没超时的情况下, test() 的返回值可以清理掉超时定时器, 避免因为 timer 引起的进程不退出, 也是避免调用那个清理操作.
其实就是两个race, 谁先跑完就把另一个清理掉… 这里拿 timer 举例的, 还可以看看 网络请求 / 文件访问这种, 如果超时, 可以 abort 网络请求, close 文件. 实例请看 https://github.com/magicdawn/yun-playlist-downloader
之前一直考虑这个回调要怎么注册, 考虑了几种方式
- 绑定在 this 上, 调用
this.cancel && this.cancel()
, 在 test 内部去实现this.cancel
. 这样问题比较多, this可能为空 / 极有可能出现公用this的情况 - 传入一个 cancel object, 让 test 去绑定
cancel.cancel
- 看到 bluebird,
onCancel
注册回调
果断选了 bluebird 的这种方式…
自顶…