MyPromise 实现
概述
本报告详细分析了一个完整的 Promise/A+ 规范实现,包括核心功能、静态方法和工具函数。该实现严格遵循 Promise/A+ 规范,并提供了与原生 Promise 兼容的 API。
Promise/A+规范:https://promisesaplus.com/
实现架构
核心组件
- MyPromise 类:主要的 Promise 实现
- resolvePromise 函数:Promise 解析程序,处理复杂的值解析逻辑
- 工具函数:辅助函数,提高代码复用性和可维护性
1. 工具函数实现
1.1 错误处理工具函数
javascript
// 工具函数 减少try catch 使用
function tryCatchFn(execFn, value, resolve, reject) {
try {
const result = execFn(value);
resolve(result);
} catch (err) {
reject(err);
}
}
实现要点:
- 统一处理回调函数的执行和异常捕获
- 减少代码重复,提高可维护性
- 确保任何回调函数抛出的异常都能被正确捕获并转换为 rejected Promise
1.2 可迭代对象检测函数
javascript
// 判断对象是否可迭代
function isIterable(obj) {
return obj !== null && obj !== undefined && typeof obj[Symbol.iterator] === "function";
}
实现要点:
- 检查
Symbol.iterator
方法的存在性 - 用于静态方法中验证参数的有效性
2. Promise 解析程序
2.1 resolvePromise 函数
javascript
// Promise解析程序
function resolvePromise(promise, value, resolve, reject) {
// 1. x 与 MyPromise 相等 防止传入自身的时候,无限循环 自引用检测
if (value === promise) {
return reject(new TypeError("循环引用"));
}
// 2. 如果 value 是 MyPromise 实例
if (value instanceof MyPromise) {
// 把当前实例的状态挂靠到 value 上
value.then(resolve, reject);
return;
}
// 3. 如果 value 是对象或者函数
if (value !== null && (typeof value === "object" || typeof value === "function")) {
let then;
try {
then = value.then;
} catch (e) {
return reject(e);
}
// 如果 then 是函数,则当作 thenable 处理
if (typeof then === "function") {
let called = false;
try {
then.call(
value,
y => {
if (called) return;
called = true;
resolvePromise(promise, y, resolve, reject); // 递归调用resolvePromise处理返回值
},
r => {
if (called) return;
called = true;
reject(r);
}
);
} catch (e) {
if (!called) reject(e);
}
return; // 进入 thenable 解析
}
}
// 4. 普通值直接resolve
resolve(value);
}
实现要点:
- 自引用检测:防止 Promise 解析自身导致的无限循环
- Promise 实例处理:通过
then
方法获取其最终状态 - Thenable 对象处理:符合 Promise/A+ 规范的 thenable 解析
- 防重复调用:使用
called
标志防止 resolve/reject 被多次调用 - 递归解析:确保嵌套的 Promise 或 thenable 都能被正确解析
3. MyPromise 核心实现
3.1 构造函数
javascript
class MyPromise {
constructor(executor) {
// 设置默认状态 pending
this.status = PROMISE_STATUS_PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledFns = [];
this.onRejectedFns = [];
const resolve = value => {
// 状态只能改变一次
if (this.status === PROMISE_STATUS_PENDING) {
// 使用 resolvePromise 处理复杂的解析逻辑
resolvePromise(
this,
value,
resolvedValue => {
this.status = PROMISE_STATUS_FULFILLED;
this.value = resolvedValue;
queueMicrotask(() => {
//将成功的回调和失败的回调放到数组中,统一对应调用
this.onFulfilledFns.forEach(fn => {
fn(this.value);
});
});
},
reject
);
}
};
const reject = reason => {
// 状态只能改变一次
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED;
this.reason = reason;
queueMicrotask(() => {
//将成功的回调和失败的回调放到数组中,统一对应调用
this.onRejectedFns.forEach(fn => {
fn(this.reason);
});
});
}
};
try {
executor(resolve, reject); // 进来立即执行 executor
} catch (err) {
reject(err);
}
}
}
实现要点:
- 状态管理:使用常量定义三种状态,确保状态只能改变一次
- 回调队列:使用数组存储待执行的回调函数
- 微任务调度:使用
queueMicrotask
确保异步执行,符合规范 - 异常处理:捕获 executor 执行时的同步异常
- 复杂值解析:委托给
resolvePromise
函数处理
3.2 then 方法实现
javascript
// 实例方法
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
// 值穿透:决定"下一个" Promise 拿到 val 以后,要不要原样再往下传。 如果没传回调,就透传 value / reason
if (typeof onFulfilled !== "function") {
onFulfilled = val => val;
}
if (typeof onRejected !== "function") {
// 直接抛出错误,实现错误穿透
onRejected = err => {
throw err;
};
}
if (this.status === PROMISE_STATUS_FULFILLED) {
queueMicrotask(() => tryCatchFn(onFulfilled, this.value, resolve, reject));
} else if (this.status === PROMISE_STATUS_REJECTED) {
queueMicrotask(() => tryCatchFn(onRejected, this.reason, resolve, reject));
} else {
this.onFulfilledFns.push(() => queueMicrotask(() => tryCatchFn(onFulfilled, this.value, resolve, reject)));
this.onRejectedFns.push(() => queueMicrotask(() => tryCatchFn(onRejected, this.reason, resolve, reject)));
}
});
}
实现要点:
- 链式调用:返回新的 Promise 实例
- 值穿透:处理未传入回调函数的情况
- 异步执行:使用
queueMicrotask
确保回调异步执行 - 状态处理:根据当前状态决定立即执行还是加入队列
- 异常处理:使用
tryCatchFn
统一处理回调异常
3.3 catch 和 finally 方法
javascript
// catch方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式。
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(onFinally) {
return this.then(
val => MyPromise.resolve(onFinally()).then(() => val),
err =>
MyPromise.resolve(onFinally()).then(() => {
throw err;
})
);
}
实现要点:
- catch 方法:简单的
then
方法封装 - finally 方法:无论成功失败都执行,且不改变原始值/原因
- 异步 finally:支持
onFinally
返回 Promise 的情况
4. 静态方法实现
4.1 resolve 和 reject
javascript
// 静态方法 只需要将包裹后的值返回出去,作为后续链式调用依靠
static resolve(value) {
return new MyPromise(resolve => resolve(value));
}
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason));
}
实现要点:
- 简洁实现:直接创建已解决/拒绝的 Promise
- 值处理:
resolve
会通过resolvePromise
处理复杂值
4.2 Promise.all 实现
javascript
static all(promises) {
if (!isIterable(promises)) {
return MyPromise.reject(new TypeError("参数必须是一个可迭代对象"));
}
const promisesArr = Array.from(promises);
const len = promisesArr.length;
if (!len) return MyPromise.resolve([]);
return new MyPromise((resolve, reject) => {
const values = [];
let count = len;
promisesArr.forEach((promise, index) => {
promise.then(val => {
values[index] = val;
if (--count === 0) resolve(values);
}, reject);
});
});
}
实现要点:
- 参数验证:检查是否为可迭代对象
- 边界处理:空数组直接返回空数组的 resolved Promise
- 并发执行:所有 Promise 并行执行
- 结果顺序:保持结果与输入顺序一致
- 快速失败:任一 Promise 失败则整体失败
4.3 Promise.allSettled 实现
javascript
static allSettled(promises) {
if (!isIterable(promises)) {
return MyPromise.reject(new TypeError("参数必须是一个可迭代对象"));
}
const promisesArr = Array.from(promises);
const len = promisesArr.length;
if (!len) return MyPromise.resolve([]);
return new MyPromise((resolve, reject) => {
const values = [];
let count = len;
promisesArr.forEach((promise, index) => {
promise.then(
val => {
values[index] = { status: PROMISE_STATUS_FULFILLED, value: val };
if (--count === 0) resolve(values);
},
err => {
values[index] = { status: PROMISE_STATUS_REJECTED, reason: err };
if (--count === 0) resolve(values);
}
);
});
});
}
实现要点:
- 永不失败:无论输入 Promise 成功失败,都会 resolve
- 结果格式:返回包含
status
和value/reason
的对象数组 - 完整等待:等待所有 Promise 都 settled
4.4 Promise.race 实现
javascript
static race(promises) {
if (!isIterable(promises)) {
return MyPromise.reject(new TypeError("参数必须是一个可迭代对象"));
}
const promisesArr = Array.from(promises);
const len = promisesArr.length;
if (!len) return MyPromise.resolve([]);
return new MyPromise((resolve, reject) => {
promisesArr.forEach(promise => {
promise.then(resolve, reject);
});
});
}
实现要点:
- 竞速机制:第一个 settled 的 Promise 决定结果
- 状态传递:直接传递第一个 settled Promise 的状态和值
4.5 Promise.any 实现
javascript
static any(promises) {
if (!isIterable(promises)) {
return MyPromise.reject(new TypeError("参数必须是一个可迭代对象"));
}
const promisesArr = Array.from(promises);
const len = promisesArr.length;
if (!len) return MyPromise.resolve([]);
return new MyPromise((resolve, reject) => {
const reasons = [];
let count = len;
promisesArr.forEach((promise, index) => {
promise.then(resolve, err => {
reasons[index] = err;
if (--count === 0) {
const AggregateError =
globalThis.AggregateError ||
function (errs) {
const e = new Error("All promises rejected");
e.errors = errs;
return e;
};
reject(new AggregateError(reasons));
}
});
});
});
}
实现要点:
- 首个成功:第一个 fulfilled 的 Promise 决定结果
- 全部失败处理:只有所有 Promise 都失败才 reject
- AggregateError:使用 AggregateError 收集所有错误,提供 polyfill
5. 完整代码
js
const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
// 工具函数 减少try catch 使用
function tryCatchFn(execFn, value, resolve, reject) {
try {
const result = execFn(value);
resolve(result);
} catch (err) {
reject(err);
}
}
// 判断对象是否可迭代
function isIterable(obj) {
return obj !== null && obj !== undefined && typeof obj[Symbol.iterator] === "function";
}
// Promise解析程序
function resolvePromise(promise, value, resolve, reject) {
// 1. x 与 MyPromise 相等 防止传入自身的时候,无限循环 自引用检测
if (value === promise) {
return reject(new TypeError("循环引用"));
}
// 2. 如果 value 是 MyPromise 实例
if (value instanceof MyPromise) {
// 把当前实例的状态挂靠到 value 上
value.then(resolve, reject);
return;
}
// 3. 如果 value 是对象或者函数
if (value !== null && (typeof value === "object" || typeof value === "function")) {
let then;
try {
then = value.then;
} catch (e) {
return reject(e);
}
// 如果 then 是函数,则当作 thenable 处理
if (typeof then === "function") {
let called = false;
try {
then.call(
value,
y => {
if (called) return;
called = true;
resolvePromise(promise, y, resolve, reject); // 递归调用resolvePromise处理返回值
},
r => {
if (called) return;
called = true;
reject(r);
}
);
} catch (e) {
if (!called) reject(e);
}
return; // 进入 thenable 解析
}
}
// 4. 普通值直接resolve
resolve(value);
}
class MyPromise {
constructor(executor) {
// 设置默认状态 pending
this.status = PROMISE_STATUS_PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledFns = [];
this.onRejectedFns = [];
const resolve = value => {
// 状态只能改变一次
if (this.status === PROMISE_STATUS_PENDING) {
// 使用 resolvePromise 处理复杂的解析逻辑
resolvePromise(
this,
value,
resolvedValue => {
this.status = PROMISE_STATUS_FULFILLED;
this.value = resolvedValue;
// console.log("resolve被调用");
queueMicrotask(() => {
// console.log("queueMicrotask-resolve-then");
//将成功的回调和失败的回调放到数组中,统一对应调用
this.onFulfilledFns.forEach(fn => {
fn(this.value);
});
});
},
reject
);
}
};
const reject = reason => {
// console.log("reject被调用");
// 状态只能改变一次
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED;
this.reason = reason;
// console.log("reject被调用");
queueMicrotask(() => {
// console.log("queueMicrotask-reject-then");
//将成功的回调和失败的回调放到数组中,统一对应调用
this.onRejectedFns.forEach(fn => {
fn(this.reason);
});
});
}
};
try {
executor(resolve, reject); // 进来立即执行 executor
} catch (err) {
reject(err);
}
}
// 实例方法
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
// 值穿透:决定“下一个” Promise 拿到 val 以后,要不要原样再往下传。 如果没传回调,就透传 value / reason
if (typeof onFulfilled !== "function") {
onFulfilled = val => val;
}
if (typeof onRejected !== "function") {
// 直接抛出错误,实现错误穿透
onRejected = err => {
throw err;
};
}
if (this.status === PROMISE_STATUS_FULFILLED) {
queueMicrotask(() => tryCatchFn(onFulfilled, this.value, resolve, reject));
} else if (this.status === PROMISE_STATUS_REJECTED) {
queueMicrotask(() => tryCatchFn(onRejected, this.reason, resolve, reject));
} else {
this.onFulfilledFns.push(() => queueMicrotask(() => tryCatchFn(onFulfilled, this.value, resolve, reject)));
this.onRejectedFns.push(() => queueMicrotask(() => tryCatchFn(onRejected, this.reason, resolve, reject)));
}
});
}
// catch方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式。
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(onFinally) {
return this.then(
val => MyPromise.resolve(onFinally()).then(() => val),
err =>
MyPromise.resolve(onFinally()).then(() => {
throw err;
})
);
// return this.then(onFinally, onFinally); // 错误的
}
// 静态方法 只需要将包裹后的值返回出去,作为后续链式调用依靠
static resolve(value) {
return new MyPromise(resolve => resolve(value));
}
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason));
}
static all(promises) {
if (!isIterable(promises)) {
return MyPromise.reject(new TypeError("参数必须是一个可迭代对象"));
}
const promisesArr = Array.from(promises);
const len = promisesArr.length;
if (!len) return MyPromise.resolve([]);
return new MyPromise((resolve, reject) => {
const values = [];
let count = len;
promisesArr.forEach((promise, index) => {
promise.then(val => {
values[index] = val;
if (--count === 0) resolve(values);
}, reject);
});
});
}
static allSettled(promises) {
if (!isIterable(promises)) {
return MyPromise.reject(new TypeError("参数必须是一个可迭代对象"));
}
// 问题关键: 什么时候要执行resolve, 什么时候要执行reject
const promisesArr = Array.from(promises);
const len = promisesArr.length;
if (!len) return MyPromise.resolve([]);
return new MyPromise((resolve, reject) => {
const values = [];
let count = len;
promisesArr.forEach((promise, index) => {
promise.then(
val => {
values[index] = { status: PROMISE_STATUS_FULFILLED, value: val };
if (--count === 0) resolve(values);
},
err => {
values[index] = { status: PROMISE_STATUS_REJECTED, reason: err };
if (--count === 0) resolve(values);
}
);
});
});
}
static race(promises) {
if (!isIterable(promises)) {
return MyPromise.reject(new TypeError("参数必须是一个可迭代对象"));
}
const promisesArr = Array.from(promises);
const len = promisesArr.length;
if (!len) return MyPromise.resolve([]);
return new MyPromise((resolve, reject) => {
promisesArr.forEach(promise => {
promise.then(resolve, reject);
});
});
}
static any(promises) {
if (!isIterable(promises)) {
return MyPromise.reject(new TypeError("参数必须是一个可迭代对象"));
}
// resolve必须等到有一个成功的结果
// reject所有的都失败才执行reject
const promisesArr = Array.from(promises);
const len = promisesArr.length;
if (!len) return MyPromise.resolve([]);
return new MyPromise((resolve, reject) => {
const reasons = [];
let count = len;
promisesArr.forEach((promise, index) => {
promise.then(resolve, err => {
reasons[index] = err;
if (--count === 0) {
const AggregateError =
globalThis.AggregateError ||
function (errs) {
const e = new Error("All promises rejected");
e.errors = errs;
return e;
};
reject(new AggregateError(reasons));
}
});
});
});
}
}
module.exports = MyPromise;
6. 设计亮点
6.1 规范遵循
- 严格遵循 Promise/A+ 规范
- 正确的异步执行时机(微任务)
- 完整的 thenable 处理逻辑
6.2 代码质量
- 模块化设计,职责分离
- 统一的错误处理机制
- 完善的边界情况处理
6.3 性能优化
- 使用
queueMicrotask
而非setTimeout
- 避免不必要的 Promise 包装
- 高效的回调队列管理
7. 总结
该 MyPromise 实现了 Promise/A+ 规范,并通过了全部872个测试用例,具有以下特点:
- 完整性:实现了所有核心功能和主要静态方法
- 规范性:严格遵循 Promise/A+ 规范
- 健壮性:完善的错误处理和边界情况处理
- 可维护性:清晰的代码结构和充分的注释
- 性能:使用了正确的异步调度机制
这个实现可以作为学习 Promise 内部机制的优秀范例,也可以在实际项目中作为 Promise 的 polyfill 使用。