手写Promise:从原理到实现的深度解析
2025.09.19 12:47浏览量:0简介:本文通过手写Promise实现,详细解析其核心机制、状态管理、链式调用及异步处理,帮助开发者深入理解Promise工作原理,提升实际开发能力。
一、面试场景中的Promise手写要求
在前端开发面试中,”手写Promise”已成为高频考点。这一要求不仅考察候选人对JavaScript异步编程的理解深度,更验证其能否将理论转化为可运行的代码实现。从企业招聘角度看,这反映了现代前端开发对基础扎实、具备底层思维工程师的需求。
二、Promise核心机制解析
1. 状态机的三态模型
Promise规范定义了三种状态:
- Pending:初始状态,可转换为Fulfilled或Rejected
- Fulfilled:操作成功完成,状态不可逆
- Rejected:操作失败,状态不可逆
这种设计遵循了”一次到位”原则,确保异步操作的确定性结果。状态转换必须通过resolve()
或reject()
方法触发,外部代码无法直接修改状态。
2. 微任务队列机制
Promise的回调执行采用微任务(Microtask)队列,优先级高于宏任务(Macrotask)。当调用then()
注册回调时,回调会被推入微任务队列,在当前执行栈清空后立即执行。这种设计避免了回调地狱,同时保证了异步操作的顺序性。
三、手写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. 状态管理实现
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());
}
};
3. 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;
}
4. 链式调用关键:resolvePromise
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);
}
}
四、完整实现代码
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) => {
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;
}
}
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);
}
}
五、实际应用建议
- 调试技巧:在实现过程中,建议使用
console.log
跟踪状态变化和回调执行顺序,这有助于理解异步流程 - 测试用例设计:
- 立即resolve/reject的测试
- 延迟resolve/reject的测试
- 链式调用的测试
- 异常处理的测试
- 性能优化:在实际项目中,可以考虑使用
queueMicrotask
替代setTimeout
实现更高效的微任务调度
六、进阶方向
- 实现
catch
、finally
等附加方法 - 添加静态方法
all
、race
、allSettled
- 支持异步生成器(Async Generator)集成
- 实现Promise的取消功能(Cancelable Promise)
通过手写Promise实现,开发者不仅能深入理解异步编程的核心机制,更能培养解决复杂问题的能力。这种底层思维在处理复杂异步场景、调试性能问题时具有不可替代的价值。建议开发者在掌握基础实现后,继续探索Promise的扩展应用,如与Async/Await的协同使用、在React/Vue中的状态管理等高级场景。
发表评论
登录后可评论,请前往 登录 或 注册