手写 Promise 先搭状态机:三个状态 pending、fulfilled、rejected 只能单向流转;then 方法返回新 Promise 实现链式调用,回调要用 try/catch 包裹以免吞掉异常;then 的参数不是函数时值要继续向下传递,这就是值穿透。resolve 与 reject 的值一旦确定不可变。
进阶手写常考 Promise.all、race、allSettled 与重试包装器。all 的要点是计数器加结果数组按索引填充,全部成功才 resolve,一个失败立即 race 出去;race 的第一个结果决定最终状态。面试时强调 then 的回调必须放进微任务队列(用 queueMicrotask 或已有的 Promise 模拟)。
// 简版 Promise:状态机 + then 链式调用 class MyPromise { constructor(executor) { this.state = 'pending'; this.value = undefined; this.cbs = []; const resolve = v => { if (this.state !== 'pending') return; this.state = 'fulfilled'; this.value = v; this.cbs.forEach(cb => cb.onFul(v)); }; const reject = r => { if (this.state !== 'pending') return; this.state = 'rejected'; this.value = r; this.cbs.forEach(cb => cb.onRej(r)); }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFul, onRej) { return new MyPromise((res, rej) => { const ful = v => { try { res(onFul ? onFul(v) : v); } catch (e) { rej(e); } }; const rej = r => { try { res(onRej ? onRej(r) : r); } catch (e) { rej(e); } }; if (this.state === 'fulfilled') ful(this.value); else if (this.state === 'rejected') rej(this.value); else this.cbs.push({ onFul: ful, onRej: rej }); }); } } new MyPromise(res => setTimeout(() => res(1), 100)) .then(v => { console.log('第一个', v); return v + 1; }) .then(v => console.log('第二个', v)); // 1 -> 2