如何结合p-cancelable与p-progress实现可取消的进度上报Promise
需求说明
需要实现同时支持执行进度上报、可主动取消的Promise,整合进度Promise、可取消Promise两类能力。单独实现任意单一能力都很简便,但组合二者时出现运行报错。
当前编写的代码可以正常上报执行进度,但运行时会抛出cancelablePromise.cancel is not a function错误。
报错原因
PProgress()调用后返回的是自身封装的Promise实例,不会自动透传内层PCancelable实例的cancel方法到外层。外层拿到的Promise实例实际为PProgress类型,本身不存在cancel方法,调用时就会触发该类型错误。
修复代码
调整doJobWithProgress函数逻辑,手动将内层可取消Promise的cancel方法绑定到外层带进度能力的Promise实例上即可,完整可运行代码如下:
import PCancelable from 'p-cancelable'; import PProgress from 'p-progress'; const cancelablePromise = doJobWithProgress(); try { cancelablePromise.onProgress((progress) => { console.log('progress: ' + progress); }); await sleep(500); cancelablePromise.cancel(); const result = await cancelablePromise; console.log("result", result); } catch (error) { console.log("Main catch error: " + error); } function sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } function doJobWithProgress() { let innerCancelable; const progressPromise = PProgress((progressCallback) => { innerCancelable = new PCancelable((resolve, reject, onCancel) => { let progress = 0; const interval = setInterval(() => { progress += 0.1; progressCallback(progress); }, 100); const timeout = setTimeout(() => { const result = 1; clearTimeout(timeout); clearInterval(interval); resolve(result); }, 1000); onCancel(() => { console.log('canceled'); clearTimeout(timeout); clearInterval(interval); }); }); return innerCancelable; }); // 将cancel方法透传到外层Promise实例 progressPromise.cancel = innerCancelable.cancel.bind(innerCancelable); return progressPromise; }
补充说明
- 修复后返回的Promise同时支持
onProgress进度监听、cancel主动取消两个核心能力,原有进度上报、取消时清理定时器的逻辑可正常运行 - 主动取消后Promise会按可取消Promise的规范抛出取消错误,可被外层catch块正常捕获
- 该实现完全符合Promise A+规范,支持
then/catch/finally等原生Promise方法的链式调用
内容的提问来源于stack exchange,提问作者Rychu
相关产品推荐
相关产品推荐

