手写实现Promise:从原理到完整代码解析
2025.09.19 12:55浏览量:0简介:本文深入解析Promise的核心机制,手写实现一个符合Promise/A+规范的完整版Promise,涵盖状态管理、链式调用、异步调度等关键功能,并提供可运行的代码示例。
手写实现Promise:从原理到完整代码解析
一、Promise的核心机制解析
Promise作为JavaScript异步编程的基石,其核心价值在于将复杂的异步操作封装为可预测的链式调用。根据ECMAScript规范,Promise对象具有三种状态:pending
(初始态)、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的基础状态管理,通过闭包保存状态和回调队列,确保状态变更的原子性。
二、链式调用的核心实现
Promise的链式调用依赖then
方法,其关键在于返回新的Promise实例,形成调用链。
2.1 then方法实现
then(onFulfilled, onRejected) {
// 参数可选处理
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
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 异步调度机制
使用setTimeout
将回调推入宏任务队列,确保:
- 符合Promise/A+规范的异步执行要求
- 避免同步调用导致的状态竞争
- 保持与原生Promise一致的调用时序
三、Promise解析过程详解
resolvePromise
函数是处理链式调用的核心,其需要处理三种特殊情况:
3.1 解析函数实现
function resolvePromise(promise2, x, resolve, reject) {
// 循环引用检测
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 防止多次调用
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);
}
}
3.2 关键处理逻辑
- Thenable对象处理:当x是具有then方法的对象时,按Promise规范处理
- 循环引用检测:防止Promise实例自我引用导致的无限循环
- 调用状态锁:通过
called
标志确保resolve/reject只调用一次
四、完整类方法实现
4.1 静态方法实现
// 静态resolve方法
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise(resolve => resolve(value));
}
// 静态reject方法
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason));
}
// 静态all方法
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let count = 0;
if (promises.length === 0) {
resolve(results);
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
count++;
if (count === promises.length) {
resolve(results);
}
},
reason => reject(reason)
);
});
});
}
4.2 实例方法扩展
// catch方法实现
catch(onRejected) {
return this.then(null, onRejected);
}
// finally方法实现
finally(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
reason => MyPromise.resolve(callback()).then(() => { throw reason; })
);
}
五、测试验证与规范符合性
使用Promises/A+测试套件验证实现:
# 安装测试工具
npm install promises-aplus-tests -g
# 创建适配层
function adapter(promise) {
return {
then: (onFulfilled, onRejected) => {
return promise.then(onFulfilled, onRejected);
}
};
}
# 运行测试
promises-aplus-tests ./adapter.js
六、性能优化建议
- 微任务调度:可使用
MutationObserver
或queueMicrotask
替代setTimeout
提升性能 - 内存优化:在状态变更后清空回调队列
- 错误边界处理:添加全局未捕获异常处理器
七、实际应用场景示例
// 图片懒加载实现
function loadImage(url) {
return new MyPromise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`Image load failed: ${url}`));
img.src = url;
});
}
// 分页数据加载
function fetchPage(page) {
return new MyPromise(resolve => {
setTimeout(() => {
resolve({ page, data: Array(10).fill(0).map((_,i)=>i+page*10) });
}, 500);
});
}
通过手写实现Promise,开发者不仅能深入理解异步编程的核心机制,更能获得以下收益:
- 精准控制异步流程的执行时序
- 自定义错误处理和调试钩子
- 针对特定场景的性能优化
- 与现有异步库的无缝集成能力
完整实现代码约200行,通过模块化设计可轻松扩展为支持取消、超时等高级功能的增强版Promise库。
发表评论
登录后可评论,请前往 登录 或 注册