如何实现JavaScript Promise的reRun方法以重执行所有thenable处理器?
实现可重跑的Promise(支持重新触发所有then/finally回调)
原生Promise一旦进入已完成(fulfilled)或已拒绝(rejected)状态就无法改变,因此无法直接让已绑定的then/finally回调重新执行。我们需要自定义一个继承原生Promise的类,通过保存执行逻辑和回调队列的方式实现reRun方法。
实现代码
class ReRunnablePromise extends Promise { constructor(executor) { super(executor); // 保存原始执行器逻辑 this.executor = executor; // 存储所有绑定的then/finally回调 this.callbacks = []; } // 重写then方法,保存回调后调用原生then then(onFulfilled, onRejected) { this.callbacks.push({ type: 'then', onFulfilled: typeof onFulfilled === 'function' ? onFulfilled : undefined, onRejected: typeof onRejected === 'function' ? onRejected : undefined }); return super.then(onFulfilled, onRejected); } // 重写finally方法,保存回调后调用原生finally finally(callback) { if (typeof callback === 'function') { this.callbacks.push({ type: 'finally', callback }); } return super.finally(callback); } // 实现reRun方法:重新执行原始逻辑并触发所有回调 reRun() { // 创建新的Promise实例,执行原始逻辑 let currentPromise = new Promise(this.executor); // 依次绑定所有保存的回调 for (const cb of this.callbacks) { if (cb.type === 'then') { currentPromise = currentPromise.then(cb.onFulfilled, cb.onRejected); } else if (cb.type === 'finally') { currentPromise = currentPromise.finally(cb.callback); } } // 返回新的Promise链,支持后续链式调用(可选) return currentPromise; } // 静态resolve方法,兼容原生Promise.resolve的使用方式 static resolve(value) { return new ReRunnablePromise(resolve => resolve(value)); } // 静态reject方法,同理 static reject(reason) { return new ReRunnablePromise((_, reject) => reject(reason)); } }
使用示例
// 用自定义类创建可重跑的Promise const promise = ReRunnablePromise.resolve(1); // 绑定多个then和finally回调 promise.then(value => { console.log(value); // 第一次输出1 return value + 1; }).then(value => { console.log(value); // 第一次输出2 }); promise.finally(() => { console.log('finally回调触发'); // 第一次输出 }); // 调用reRun,重新触发所有回调 promise.reRun(); // 此时会再次输出:1、2、finally回调触发
核心逻辑说明
- 继承原生Promise保证了所有原生Promise的特性(异步执行、链式调用、catch方法等)。
- 每次调用
then/finally时,会将回调函数存入内部队列,同时正常执行原生方法保持原有行为。 reRun方法会重新创建一个执行原始逻辑的Promise,然后将队列中所有回调依次绑定到新Promise上,从而让所有回调重新执行。- 对于异步的执行逻辑(比如包含setTimeout),每次
reRun都会重新触发异步流程,符合预期。
内容的提问来源于stack exchange,提问作者user10965730
相关产品推荐
相关产品推荐

