《JS Promise 实现原理 - 手写符合 Promises/A+ 规范的异步解决方案》
在 JavaScript 异步编程中,Promise 是核心机制之一。它解决了回调地狱(Callback Hell)问题,提供了链式调用、错误处理等能力。本文将深入解析 Promise 的实现原理,并手写一个符合 Promises/A+ 规范的 Promise 类,帮助读者理解其底层逻辑。
一、Promise 的核心概念
Promise 是一个对象,表示异步操作的最终完成(或失败)及其结果值。它有三种状态:
- Pending(待定):初始状态,既未完成,也未拒绝。
- Fulfilled(已兑现):操作成功完成。
- Rejected(已拒绝):操作失败。
状态一旦改变,就不能再变(从 Pending 到 Fulfilled 或 Rejected)。
二、Promises/A+ 规范要点
Promises/A+ 是 Promise 的通用规范,定义了以下核心行为:
- Then 方法:Promise 必须实现 `.then()` 方法,接受两个可选参数(onFulfilled、onRejected)。
- 链式调用:`.then()` 返回一个新的 Promise,实现链式调用。
- 异步执行:onFulfilled/onRejected 必须异步调用(通过微任务或宏任务)。
- 错误传播:若 onFulfilled/onRejected 抛出异常,返回的 Promise 应被拒绝。
三、手写 Promise 实现
以下是一个简化版的 Promise 实现,符合 Promises/A+ 规范:
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);
}
}
}
2. 实现 .then() 方法
.then() 需要返回一个新的 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 模拟微任务)
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
} else if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
} else if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
}
});
return promise2;
}
3. resolvePromise 函数
处理 Promise 解析规则(如返回值是 Promise 时的递归解析):
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 (err) {
if (called) return;
called = true;
reject(err);
}
} else {
resolve(x);
}
}
4. 静态方法:resolve、reject、all、race
// MyPromise.resolve
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise(resolve => resolve(value));
}
// MyPromise.reject
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
// MyPromise.all
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let count = 0;
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
count++;
if (count === promises.length) resolve(results);
},
reject
);
});
});
}
// MyPromise.race
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve, reject);
});
});
}
四、测试与验证
使用以下代码验证实现:
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => resolve('Success!'), 1000);
});
promise
.then(value => {
console.log(value); // 输出: Success!
return 'Next Value';
})
.then(value => {
console.log(value); // 输出: Next Value
});
五、与原生 Promise 的对比
原生 Promise 的实现更复杂,例如:
- 使用微任务队列(如 `queueMicrotask` 或 `MutationObserver`)而非 `setTimeout`。
- 优化了性能和内存占用。
- 支持更多边缘情况(如 `then` 的多次调用)。
六、关键点总结
- 状态不可逆:一旦从 Pending 变为 Fulfilled/Rejected,不能再次改变。
- 异步执行:回调必须通过微任务/宏任务延迟执行。
- 链式调用:`.then()` 返回新 Promise,实现方法链。
- 错误传播:未捕获的异常会传递到下一个 `.then()` 的 `onRejected`。
关键词:JavaScript、Promise、Promises/A+ 规范、异步编程、手写实现、状态管理、链式调用、错误处理
简介:本文详细解析了 JavaScript 中 Promise 的核心原理,并手写了一个符合 Promises/A+ 规范的 Promise 类。内容涵盖状态管理、.then() 方法实现、链式调用、异步执行、错误传播等关键点,同时对比了原生 Promise 的实现差异,适合希望深入理解 Promise 机制的开发者。