可能是目前最易理解的手写Promise:从原理到实现全解析
2025.09.19 12:47浏览量:0简介:本文通过分步拆解Promise核心机制,结合代码示例与状态转换图,用最直观的方式讲解如何手写一个符合A+规范的Promise。涵盖异步任务管理、链式调用、错误处理等关键功能,并提供可运行的完整实现代码。
可能是目前最易理解的手写Promise:从原理到实现全解析
一、为什么需要手写Promise?
在前端开发中,Promise已成为处理异步操作的标准方案。但多数开发者仅停留在then/catch
的表面使用,对内部实现机制缺乏深入理解。手写Promise不仅能加深对异步编程的理解,更能帮助解决以下实际问题:
- 调试困难:当Promise链中出现意外行为时,理解实现原理能快速定位问题
- 性能优化:自定义实现可针对性优化特定场景的异步流程
- 框架开发:构建底层库时需要精确控制异步行为
- 面试考察:手写Promise是高级前端岗位的常见考察点
本文将通过最简化的实现路径,逐步构建一个符合Promise/A+规范的完整实现,确保每个步骤都有明确的解释。
二、Promise核心机制解析
1. 状态机模型
Promise本质是一个状态机,包含三种状态:
- Pending(待定):初始状态,可迁移到Fulfilled或Rejected
- Fulfilled(已兑现):表示操作成功完成
- Rejected(已拒绝):表示操作失败
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(executor) {
this.state = PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
}
}
状态转换规则:
- 只能从Pending迁移到Fulfilled或Rejected
- 一旦状态改变,不可再次变更
- 状态变更必须通过
resolve
或reject
方法触发
2. 异步任务队列
Promise通过维护两个回调队列实现异步处理:
resolve = (value) => {
if (this.state === PENDING) {
this.state = FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
reject = (reason) => {
if (this.state === PENDING) {
this.state = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
这种设计确保了:
- 同步执行的executor函数可以立即触发状态变更
- 异步执行的executor会将回调推入队列,在微任务中执行
三、分步实现完整Promise
1. 基础结构搭建
class MyPromise {
constructor(executor) {
this.state = PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
// 实现待补充
};
const reject = (reason) => {
// 实现待补充
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
}
2. 实现then方法
then
方法是Promise的核心,需要处理:
- 立即返回新Promise实现链式调用
- 执行时机控制(微任务)
- 值穿透机制
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;
}
3. 解析Promise链(resolvePromise)
这是实现Promise规范最关键的部分,需要处理:
- 循环引用检测
- thenable对象处理
- 异常捕获
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);
}
}
四、完整实现代码
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
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);
}
}
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 handleFulfilled = () => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
const handleRejected = () => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === FULFILLED) {
handleFulfilled();
} else if (this.state === REJECTED) {
handleRejected();
} else if (this.state === PENDING) {
this.onFulfilledCallbacks.push(handleFulfilled);
this.onRejectedCallbacks.push(handleRejected);
}
});
return promise2;
}
// 添加catch方法增强实用性
catch(onRejected) {
return this.then(null, onRejected);
}
// 添加静态resolve方法
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise(resolve => resolve(value));
}
}
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);
}
}
五、实用建议与扩展
测试验证:使用Promises/A+测试套件验证实现正确性
npm install promises-aplus-tests -g
promises-aplus-tests your-promise-implementation.js
性能优化:
- 使用
queueMicrotask
替代setTimeout
实现更精确的微任务调度 - 对频繁创建的Promise进行对象池管理
- 使用
扩展功能:
- 实现
finally
方法 - 添加
all
、race
等静态方法 - 支持取消Promise的机制
- 实现
调试技巧:
- 在状态变更时添加日志
- 实现
inspect
方法便于调试
六、总结
通过分步实现,我们构建了一个符合Promise/A+规范的完整实现。关键点包括:
- 严格的三态管理机制
- 异步回调队列的实现
- 链式调用的值穿透处理
- thenable对象的解析规则
这种实现方式不仅加深了对Promise原理的理解,更为自定义异步控制提供了基础。实际开发中,可根据具体需求在此基础上进行扩展优化,构建更符合业务场景的异步解决方案。
发表评论
登录后可评论,请前往 登录 或 注册