手写Promise全解析:从基础实现到Promises/A+测试通关
2025.09.19 12:56浏览量:0简介:本文深入解析如何手写实现Promise并满足Promises/A+规范,通过代码示例和测试用例详解核心机制,帮助开发者掌握异步编程的底层原理。
手写Promise全解析:从基础实现到Promises/A+测试通关
一、Promise核心机制解析
Promise作为现代JavaScript异步编程的核心,其设计遵循”状态机”理论。一个Promise对象必然处于以下三种状态之一:
- Pending(待定):初始状态,可迁移至Fulfilled或Rejected
- Fulfilled(已兑现):表示操作成功完成
- Rejected(已拒绝):表示操作失败
状态迁移具有不可逆性,这是实现Promise时必须严格遵守的规范。以文件读取操作为例,当fs.readFile
成功完成时,Promise应进入Fulfilled状态并携带文件内容;若发生错误则进入Rejected状态并携带错误对象。
1.1 基础类结构实现
class MyPromise {
constructor(executor) {
this.state = 'pending'; // 初始状态
this.value = undefined; // 成功值
this.reason = undefined; // 失败原因
this.onFulfilledCallbacks = []; // 成功回调队列
this.onRejectedCallbacks = []; // 失败回调队列
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
}
这个基础实现包含了Promise的核心机制:状态管理、异步回调队列和错误捕获。值得注意的是,resolve和reject函数必须进行状态检查,防止重复状态变更。
二、then方法实现与链式调用
then方法是Promise实现中最复杂的部分,需要处理三种关键场景:
- 立即返回新Promise:实现链式调用的基础
- 回调函数异步执行:符合规范要求的微任务特性
- 值穿透机制:处理非函数回调的情况
2.1 完整then方法实现
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 (e) {
reject(e);
}
}, 0);
} else if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
} else if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
2.2 关键辅助函数:resolvePromise
这个函数处理Promise链式调用中的值传递,需要遵循以下规则:
- 如果x是Promise实例,则等待其决议
- 如果x是对象或函数,尝试解析其then方法
- 否则直接resolve(x)
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
let called = false;
if (x !== null && (typeof x === 'object' || 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 (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
三、Promises/A+规范测试实现
Promises/A+测试套件包含288个测试用例,验证实现是否符合规范。测试环境搭建步骤如下:
3.1 测试环境配置
安装测试运行器:
npm install promises-aplus-tests -D
创建适配器文件
promise-adapter.js
:
```javascript
const MyPromise = require(‘./my-promise’);
module.exports = {
deferred: () => {
let resolve, reject;
const promise = new MyPromise((res, rej) => {
resolve = res;
reject = rej;
});
return {
promise,
resolve,
reject
};
}
};
3. 运行测试:
```bash
npx promises-aplus-tests promise-adapter.js
3.2 关键测试点解析
测试套件主要验证以下方面:
- 状态变更:确保状态只能从pending变为fulfilled/rejected
- 回调执行:验证then方法在状态变更后正确执行回调
- 链式调用:测试Promise链的传递和值穿透
- 异常处理:验证同步和异步错误的捕获机制
典型测试用例示例:
// 测试用例:then方法返回新Promise
it('should return a new promise', (done) => {
const deferred = adapter.deferred();
const result = deferred.promise.then(() => {});
assert(result instanceof Promise, 'then should return a Promise');
deferred.resolve();
done();
});
四、高级特性实现
4.1 静态方法实现
// catch方法
catch(onRejected) {
return this.then(null, onRejected);
}
// resolve静态方法
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise(resolve => resolve(value));
}
// reject静态方法
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
// all方法
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let completed = 0;
if (promises.length === 0) {
resolve(results);
return;
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
completed++;
if (completed === promises.length) {
resolve(results);
}
},
reject
);
});
});
}
4.2 微任务调度优化
实际实现中,可以使用queueMicrotask
或MutationObserver
来模拟微任务队列:
const microtaskQueue = [];
let isFlushing = false;
function flushMicrotasks() {
if (isFlushing) return;
isFlushing = true;
while (microtaskQueue.length) {
const callback = microtaskQueue.shift();
callback();
}
isFlushing = false;
}
// 替换setTimeout
function scheduleMicrotask(callback) {
microtaskQueue.push(callback);
if (!isFlushing) {
Promise.resolve().then(flushMicrotasks);
}
}
五、性能优化与最佳实践
- 内存管理:在状态变更后清空回调队列
- 错误边界:使用try-catch包裹所有同步操作
- 调试支持:添加Promise链跟踪信息
- 兼容性处理:处理thenable对象的特殊情况
优化后的resolve函数示例:
const resolve = (value) => {
if (this.state !== 'pending') return;
// 处理thenable对象
if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
try {
const then = value.then;
if (typeof then === 'function') {
then.call(value, resolve.bind(this), reject.bind(this));
return;
}
} catch (e) {
reject.call(this, e);
return;
}
}
this.state = 'fulfilled';
this.value = value;
// 清空回调队列节省内存
this.onFulfilledCallbacks = [];
scheduleMicrotask(() => this.onFulfilledCallbacks.forEach(fn => fn()));
};
六、总结与进阶建议
实现符合Promises/A+规范的Promise需要深入理解:
- 状态机的不可逆性
- 异步执行的调度机制
- 链式调用的值传递规则
- 异常处理的边界条件
建议开发者:
- 优先理解规范文档,再着手实现
- 逐步实现功能,先保证基础then方法正确
- 使用测试套件验证实现
- 参考成熟实现(如promises-es6)学习优化技巧
完整实现代码约200行,通过测试套件验证后,可应用于生产环境中的简单场景。对于复杂需求,建议使用经过充分测试的库如Bluebird或Zoroaster。
发表评论
登录后可评论,请前往 登录 或 注册