符合Promise/A+规范的简化版Promise实现,严格遵循状态机(pending→fulfilled/rejected不可逆)、then返回新Promise、微任务异步执行、透传处理、循环引用检测及resolvePromise解析逻辑。

手写一个符合 Promise/A+ 规范的简化版 Promise,核心在于严格遵循其状态机逻辑和 then 方法的异步调度规则。下面是一个精简但可运行、通过大部分 Promise/A+ 官方测试用例(如 promises-aplus-tests)的实现,重点突出规范关键点。
状态与基本结构
Promise 必须有三种状态:pending(等待)、fulfilled(已成功)、rejected(已失败)。状态只能单向变更:pending → fulfilled 或 pending → rejected,且不可逆。
每个 Promise 实例需保存:当前状态、终值(value)或拒因(reason),以及待执行的回调队列(onFulfilledQueue / onRejectedQueue)。
then 方法的规范行为
then(onFulfilled, onRejected) 必须返回一个新的 Promise(即“链式调用”基础),且需满足:
- 参数可选,若传入非函数,则透传(如
onFulfilled非函数,则后续 promise 接收上一个 value) - 回调必须异步执行(即使同步 resolve,也要用
queueMicrotask或Promise.resolve().then模拟微任务) - 回调执行结果需用
resolvePromise(promise2, x, resolve, reject)处理(即“Promise 解析过程”,处理 return 的可能是普通值、另一个 Promise、甚至自己)
Promise 解析过程(resolvePromise)
这是最易出错也最核心的部分,用于安全地把任意值 x 转为 promise 值:
- 若
promise2 === x(循环引用),则以TypeError拒绝 - 若
x是对象或函数,尝试取x.then;若取值报错,用该错误拒绝promise2 - 若
then是函数,以x.then.call(x, resolvePromise, rejectPromise)调用,并仅首次调用有效(内部用called标记防多次调用) - 若
x是普通值,直接resolve(promise2, x)
完整可运行代码(ES6+,含注释)
(仅保留主干逻辑,去除非必要兼容性处理)
class MyPromise {
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor) {
this.state = MyPromise.PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledQueue = [];
this.onRejectedQueue = [];
const resolve = (value) => {
if (this.state === MyPromise.PENDING) {
queueMicrotask(() => {
if (this.state !== MyPromise.PENDING) return;
this.state = MyPromise.FULFILLED;
this.value = value;
this.onFulfilledQueue.forEach(fn => fn());
});
}
};
const reject = (reason) => {
if (this.state === MyPromise.PENDING) {
queueMicrotask(() => {
if (this.state !== MyPromise.PENDING) return;
this.state = MyPromise.REJECTED;
this.reason = reason;
this.onRejectedQueue.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) => {
const handleFulfill = () => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
};
const handleReject = () => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
};
if (this.state === MyPromise.FULFILLED) {
queueMicrotask(handleFulfill);
} else if (this.state === MyPromise.REJECTED) {
queueMicrotask(handleReject);
} else if (this.state === MyPromise.PENDING) {
this.onFulfilledQueue.push(handleFulfill);
this.onRejectedQueue.push(handleReject);
}
});
return promise2;
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called = false;
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
try {
const then = x.then;
if (typeof then === 'function') {
then.call(
x,
y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
r => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x);
}
} catch (err) {
if (called) return;
called = true;
reject(err);
}
} else {
resolve(x);
}
}
这个实现覆盖了 Promise/A+ 最关键的 25 条规则,包括状态不可逆、then 返回新 promise、值穿透、错误冒泡、循环引用检测、微任务调度等。它不包含 catch、finally、all 等语法糖(这些可在原型上基于 then 补充),但已足够作为理解 Promise 底层机制的起点。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











