最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何手动编写一个具备 .then 与 .catch 链式调用功能的简单 Promise
时间:2026-07-21 11:24:55 编辑:袖梨 来源:一聚教程网
手动实现 Promise 需在构造函数中维护 pending/fulfilled/rejected 三种状态、value/reason 值及 onFulfilledCallbacks/onRejectedCallbacks 回调数组;.then 必返回新 Promise 并通过 resolvePromise 统一处理返回值;.catch 是 .then(null, onRejected) 的语法糖;所有回调需用 queueMicrotask 或 Promise.resolve().then 做微任务调度以符合规范。
Promise 构造函数里要存什么状态和回调
手动实现 Promise,核心是管理三个状态:pending、fulfilled、rejected,以及在状态变更时触发的回调队列。不能只存一个回调,因为 .then 可能被多次调用,每次都要排队等执行。
构造函数接收一个执行器函数 executor,它立即同步执行,并传入 resolve 和 reject 两个函数。这两个函数不能直接返回值,而是用来改变实例内部状态并触发对应队列。
-
resolve只在状态为pending时才生效,把状态设为fulfilled,保存value,然后遍历执行onFulfilledCallbacks -
reject同理,设为rejected,保存reason,执行onRejectedCallbacks - 回调队列必须是数组,且每个元素是函数(不是执行结果),否则无法支持链式调用中后续
.then的注册
如何让 .then 返回新 Promise 实现链式调用
.then 必须返回一个新的 Promise 实例,这是链式调用的基础。否则 promise.then(...).then(...) 第二个 .then 就会报错 —— 因为第一个 .then 如果返回普通值或没返回,就不是 Promise。
这个新 Promise 的状态,取决于上一个 .then 里回调函数的执行结果:
- 如果回调返回一个
Promise(比如return new MyPromise(...)),新Promise应该等待它结束,并继承其状态和值 - 如果回调抛出错误,新
Promise立即变为rejected - 如果回调返回普通值(包括
undefined),新Promise变为fulfilled,值就是该返回值
所以 .then 内部需要调用一个辅助函数(常叫 resolvePromise)来统一处理返回值,避免重复逻辑。
为什么 .catch 是 .then(null, onRejected) 的语法糖
.catch 本身不参与状态流转,它只是把 onRejected 回调透传给 .then 的第二个参数。所以最简实现就是:catch(onRejected) { return this.then(null, onRejected); }
但要注意:如果 .then 的 onFulfilled 回调里抛错,这个错误会被后续的 .catch 捕获,因为错误会向下穿透到最近的 onRejected 处理器 —— 这依赖于 .then 返回的新 Promise 在执行回调出错时自动 reject。
- 不要在
.catch里重新 throw 错误却不返回新Promise,否则链会断 - 如果
.catch回调自己返回值(比如修复后返回默认数据),那后续.then会收到这个值,状态是fulfilled -
Promise.prototype.catch = function(onRejected) { return this.then(undefined, onRejected); };是合法且等价的写法
常见陷阱:异步执行时机与微任务队列模拟
原生 Promise 的 then 回调属于微任务(microtask),总在当前宏任务结束后、下次渲染前执行。手动实现时若用 setTimeout,就变成了宏任务,行为不一致。
可以用 queueMicrotask(现代环境)或降级用 Promise.resolve().then 模拟微任务调度:
function nextTick(fn) { if (typeof queueMicrotask === 'function') { queueMicrotask(fn); } else { Promise.resolve().then(fn); }}
所有状态变更后的回调执行(比如 resolve 后触发 onFulfilledCallbacks)都必须包裹在 nextTick 里,否则同步执行会导致顺序错乱,比如:
- new Promise((r) => { r(1); }).then(console.log); // 原生是异步输出,手动实现若同步执行就会变成同步输出
- 多个
.then注册后,它们的回调应按注册顺序在下一个微任务中执行,而非立即交错运行
微任务调度这一步最容易被忽略,但它决定了你的实现是否符合 Promise/A+ 规范的行为预期。
相关文章
- 苹果折叠屏爆料汇总:售价超两万,比例阔折叠 07-30
- 纪念碑谷3 纪念碑谷3手游玩法详解与体验评测 07-30
- 晴空双子金卡阵容推荐 晴空双子高性价比氪金养成指南 07-30
- 大周列国志全新派系系统 07-30
- 兔小萌世界甜系小房间搭建指南 兔小萌世界高颜值甜系房间布置全流程详解 07-30
- 大周列国志全新剧本包西汉剧本包 07-30