11、手写简版promise,基础架子,不用写all、race等api

张开发
2026/4/17 3:51:09 15 分钟阅读

分享文章

11、手写简版promise,基础架子,不用写all、race等api
目录一、核心功能二、先给一个可面试用的简版实现三、使用示例1. 同步 resolve2. 异步 resolve3. 链式调用四、代码拆解说明1. 为什么要有状态2. 为什么要存回调数组3. 为什么 then 要返回新 Promise4. 为什么 then 里要 try...catch5. 为什么用 setTimeout五、这个版本的不足1. then 返回值如果还是 Promise2. 没处理循环引用3. 没实现 catch六、如果你想稍微更完整一点稍完整版七、面试时怎么讲1. 先说 Promise 的核心特性2. 说构造函数做什么3. 说异步场景怎么处理4. 说 then 为什么返回新 Promise5. 说简版和完整版差异八、最适合“基础架子”的版本九、一句话总结如果题目要求只写基础架子不用实现all / race / finally等 API重点实现new Promise(executor)resolverejectthen那可以写一个简版 Promise。一、核心功能一个基础 Promise 至少要支持三种状态pendingfulfilledrejected状态一旦改变不能再改构造函数立即执行 executornew MyPromise((resolve, reject) { // 这里会立刻执行 });then 可以注册成功/失败回调异步任务完成后执行对应回调then 支持链式调用二、先给一个可面试用的简版实现class MyPromise { constructor(executor) { this.state pending; this.value undefined; this.reason undefined; this.onFulfilledCallbacks []; this.onRejectedCallbacks []; const resolve (value) { if (this.state ! pending) 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) { onFulfilled typeof onFulfilled function ? onFulfilled : value value; onRejected typeof onRejected function ? onRejected : reason { throw reason; }; const promise2 new MyPromise((resolve, reject) { if (this.state fulfilled) { setTimeout(() { try { const x onFulfilled(this.value); resolve(x); } catch (err) { reject(err); } }, 0); } if (this.state rejected) { setTimeout(() { try { const x onRejected(this.reason); resolve(x); } catch (err) { reject(err); } }, 0); } if (this.state pending) { this.onFulfilledCallbacks.push(() { setTimeout(() { try { const x onFulfilled(this.value); resolve(x); } catch (err) { reject(err); } }, 0); }); this.onRejectedCallbacks.push(() { setTimeout(() { try { const x onRejected(this.reason); resolve(x); } catch (err) { reject(err); } }, 0); }); } }); return promise2; } }三、使用示例1. 同步 resolveconst p new MyPromise((resolve, reject) { resolve(100); }); p.then(res { console.log(res); // 100 });2. 异步 resolveconst p new MyPromise((resolve, reject) { setTimeout(() { resolve(success); }, 1000); }); p.then(res { console.log(res); // success });3. 链式调用new MyPromise((resolve) { resolve(1); }) .then(res { console.log(res); // 1 return res 1; }) .then(res { console.log(res); // 2 return res 1; }) .then(res { console.log(res); // 3 });四、代码拆解说明1. 为什么要有状态this.state pending;Promise 状态只能从pending - fulfilledpending - rejected一旦成功或失败就不能再改。所以在resolve/reject里都要判断if (this.state ! pending) return;2. 为什么要存回调数组因为很多 Promise 是异步的。比如const p new MyPromise((resolve) { setTimeout(() { resolve(1); }, 1000); }); p.then(res console.log(res));执行then的时候Promise 还没成功所以不能立刻调用回调。因此要先把回调存起来this.onFulfilledCallbacks []; this.onRejectedCallbacks [];等将来状态改变时再统一执行。3. 为什么 then 要返回新 Promise因为要支持链式调用p.then(...).then(...).then(...)所以then必须返回一个新的 Promise。const promise2 new MyPromise((resolve, reject) { ... }); return promise2;4. 为什么 then 里要 try...catch如果回调执行报错p.then(() { throw new Error(fail); });那么新的 Promise 应该走reject。所以try { const x onFulfilled(this.value); resolve(x); } catch (err) { reject(err); }5. 为什么用 setTimeoutPromise 的then回调是异步执行的。这里为了简化不实现微任务直接用setTimeout(..., 0)来模拟异步。严格规范里应该是微任务但面试写简版时一般这样就够了。五、这个版本的不足上面这个版本是基础架子版可以用于说明原理但还不完全符合 Promise/A 规范。比如还没处理这些复杂情况1. then 返回值如果还是 Promise例如p.then(() { return new MyPromise(resolve resolve(123)); });上面的简版里直接resolve(x)了没有继续“拆”这个 Promise。规范里应该判断如果x是普通值直接resolve(x)如果x是 Promise要等它的结果再决定2. 没处理循环引用例如const p2 p.then(() p2);这是规范里要报错的。3. 没实现 catch虽然可以通过then(null, errFn)代替但严格说还没单独封装catch。六、如果你想稍微更完整一点可以补一个处理返回值的函数resolvePromise。这样链式调用会更像真正的 Promise。稍完整版function resolvePromise(promise2, x, resolve, reject) { if (promise2 x) { return reject(new TypeError(Chaining cycle detected)); } if (x instanceof MyPromise) { x.then(resolve, reject); } else { resolve(x); } } class MyPromise { constructor(executor) { this.state pending; this.value undefined; this.reason undefined; this.onFulfilledCallbacks []; this.onRejectedCallbacks []; const resolve (value) { if (this.state ! pending) 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) { onFulfilled typeof onFulfilled function ? onFulfilled : value value; onRejected typeof onRejected function ? onRejected : reason { throw reason; }; const promise2 new MyPromise((resolve, reject) { if (this.state fulfilled) { setTimeout(() { try { const x onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (err) { reject(err); } }, 0); } if (this.state rejected) { setTimeout(() { try { const x onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (err) { reject(err); } }, 0); } if (this.state pending) { this.onFulfilledCallbacks.push(() { setTimeout(() { try { const x onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (err) { reject(err); } }, 0); }); this.onRejectedCallbacks.push(() { setTimeout(() { try { const x onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (err) { reject(err); } }, 0); }); } }); return promise2; } catch(onRejected) { return this.then(null, onRejected); } }七、面试时怎么讲你可以按这个结构回答1. 先说 Promise 的核心特性Promise 核心有三种状态pending、fulfilled、rejected状态一旦变化就不可逆。2. 说构造函数做什么在构造函数里立即执行executor并传入resolve和reject。如果 executor 抛错直接 reject。3. 说异步场景怎么处理因为 Promise 可能是异步完成的所以要维护成功回调队列和失败回调队列等状态变化时再依次执行。4. 说 then 为什么返回新 Promise为了支持链式调用then必须返回一个新的 Promise。新 Promise 的状态取决于上一个then回调的返回值或者异常。5. 说简版和完整版差异简版主要实现状态管理、回调收集和链式调用如果要更符合规范还需要处理 then 返回 Promise、thenable 对象、循环引用、微任务调度等细节。八、最适合“基础架子”的版本如果你是面试手写面试官只要“简版基础架子”建议你写下面这个版本够清晰class MyPromise { constructor(executor) { this.state pending; this.value undefined; this.reason undefined; this.onFulfilledCallbacks []; this.onRejectedCallbacks []; const resolve (value) { if (this.state ! pending) 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 (e) { reject(e); } } then(onFulfilled, onRejected) { onFulfilled typeof onFulfilled function ? onFulfilled : value value; onRejected typeof onRejected function ? onRejected : reason { throw reason; }; return new MyPromise((resolve, reject) { if (this.state fulfilled) { setTimeout(() { try { const result onFulfilled(this.value); resolve(result); } catch (e) { reject(e); } }, 0); } if (this.state rejected) { setTimeout(() { try { const result onRejected(this.reason); resolve(result); } catch (e) { reject(e); } }, 0); } if (this.state pending) { this.onFulfilledCallbacks.push(() { setTimeout(() { try { const result onFulfilled(this.value); resolve(result); } catch (e) { reject(e); } }, 0); }); this.onRejectedCallbacks.push(() { setTimeout(() { try { const result onRejected(this.reason); resolve(result); } catch (e) { reject(e); } }, 0); }); } }); } }九、一句话总结手写简版 Promise 的核心就是状态管理 回调缓存 then 链式调用。

更多文章