以下是实现支持取消机制的Promise链式调用的完整方案,结合Promise核心原理与取消控制逻辑:
一、核心实现原理
1.状态机控制
-
通过pending/fulfilled/rejected三态管理异步流程
-
取消时强制状态转为rejected并触发终止信号
2.链式调用基础
-
then方法返回新Promise实例实现链式衔接
-
回调队列管理确保执行顺序
3.取消机制设计
-
标志位法:通过外部变量控制执行中断
-
AbortController:适用于fetch等场景的标准化取消
-
Pending冻结:返回永久pending的Promise阻断链路
二、完整代码实现
class CancelablePromise{
constructor(executor){
this.state = "pending";
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
this.isCancelled = false;
const resolve = (value) =>{
if(this.state !=='pending' || this.isCancelled) return ;
this.state='fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn =>fn());
};
const reject = (reason) =>{
if(this.state !=='pending') return ;
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn =>fn());
};
try{
executor(resolve,reject);
}catch(err){
reject(err);
}
}
then(onFulfilled,onRejected){
return new CancelablePromise((resolve,reject)=>{
const wrappedOnFulfilled = ()=>{
if(this.isCancelled) return reject(new Error('Promise cancelled'));
try{
const x = onFulfilled?.(this.value);
resolve(x);
}catch(e){
reject(e);
}
}
const wrappedOnRejected = ()=>{
try{
const x = onRejected?.(this.reason);
resolve(x)
}catch(e){
reject(e)
}
}
if(this.state ==='fulfilled'){
setTimeout(wrappedOnFulfilled,0)
}else if(this.state ==='rejected'){
setTimeout(wrappedOnRejected,0)
}else{
this.onFullfilledCallbacks.push(wrappedOnFulfilled);
this.onRejectedCallbacks.push(wrappedOnRejected)
}
})
}
cancel(){
this.isCancelled = true;
this.reject(new Error('Promise canceled by user'))
}
}
三、关键功能说明
1.取消触发点
-
调用cancel()方法后立即终止后续链式调用
-
已进入执行队列的任务不会被中断(需配合AbortController实现)
2.异常处理
-
取消操作自动触发reject传播至最近catch节点
-
支持自定义取消错误类型识别
3.链式兼容性
-
保持与原生Promise相同的then/catch语法
-
支持async/await语法糖调用
四、使用示例
const p = new CancelablePromise(resolve => {
setTimeout(() => resolve('Done'), 1000);
})
.then(console.log)
.catch(err => console.log('Error:', err.message));
// 取消执行
setTimeout(() => p.cancel(), 500);
// 输出: Error: Promise cancelled by user