Promise/A+规范的背景
Promise/A+规范 是一个开源社区制定的标准,旨在为 JavaScript中的Promise提供一致、可靠的实现指南(标准)。它起源于早期的Promise实现(如Promise/A、Promise/B等),为了解决不同库之间的互操作性问题(早期各种三方库都各自实现了自己的Promise或类似机制),社区在2013年制定了Promise/A+规范,作为一个简洁、明确的标准。
Promise/A+规范的核心术语
Promise/A+规范使用了一些关键术语:
- Promise:一个具有
then方法的对象或函数,行为符合Promise/A+规范。 - thenable:一个定义了
then的对象或函数(可以被Promise识别并处理)。 - value:Promise兑现(fulfilled)时返回的任意合法JavaScript值(包括
undefined、thenable或Promise)。 - reason:Promise拒绝(rejected)时提供的错误原因。
- exception:在Promise执行过程中抛出的异常。
Promise的状态
Promise/A+规范定义了Promise的三种状态(与JavaScript Promise一致):
- Pending(待定) :初始状态Promise尚未完成。
- Fulfilled(已兑现) :Promise已成功完成,携带一个value。
- Rejected(已拒绝) :Promise已失败,携带一个reason。
状态规则:
- Promise必须处于三种状态之一。
- 状态只能从Pending转换为Fulfilled或Rejected一旦改变不可逆。
- 如果状态为Fulfilled,必须有一个不可变的
value。 - 如果状态为Rejected,必须有一个不可变的
reason。
then方法的核心要求
Promise/A+规范的核心是then方法的行为定义。then方法时Promise的主要接口,用于注册回调函数处理Fulfilled或Rejected状态。
then方法的签名
promise.then(onFulfilled, onRejected);
- onFulfilled:当 Promise 变为 Fulfilled 时调用的函数,接收
value作为参数。 - onRejected:当 Promise 变为 Rejected 时调用的函数,接收
reason作为参数。 - 两个参数都是可选的(可以是
undefined或非函数)。
then方法的要求
-
返回新的Promise:
promise.then(onFulfilled, onRejected)必须返回一个新的Promise(成为promise2)- 这样支持链式调用(如
promise.then().then())
-
onFulfilled和onRejected的调用规则:
-
如果
onFulfilled不是函数且 Promise 为 Fulfilled,则promise2必须以相同的value兑现。 -
如果
onRejected不是函数且 Promise 为 Rejected,则promise2必须以相同的reason拒绝。 -
如果
onFulfilled或onRejected是函数:- 它们必须在 Promise 状态确定后调用(异步执行)。
- 它们只能被调用一次。
onFulfilled接收value作为第一个参数,onRejected接收reason作为第一个参数。
-
-
异步执行:
onFulfilled和onRejected必须作为异步任务执行(通常通过微任务队列,如 JavaScript 中的queueMicrotask或setTimeout)。- 这是为了保证一致的异步行为,避免同步调用导致的复杂性。
-
返回值处理:
-
onFulfilled或onRejected的返回值(称为x)决定promise2的状态:- 如果
x是一个 Promise,则promise2等待x的状态并跟随其结果(Fulfilled 或 Rejected)。 - 如果
x是一个 thenable(具有then方法的对象),则尝试调用其then方法,并根据结果决定promise2的状态。 - 如果
x是一个普通值,promise2以x兑现。 - 如果
onFulfilled或onRejected抛出异常,promise2以该异常为reason拒绝。
- 如果
-
-
异常处理:
- 如果
onFulfilled或onRejected抛出异常,promise2必须以该异常为reason拒绝。 - 如果
promise.then本身抛出异常,promise2必须以该异常为reason拒绝。
- 如果
-
多重调用:
then方法可以被多次调用,每次调用都会创建一个新的 Promise。- 所有注册的
onFulfilled或onRejected回调都会在 Promise 状态确定后按注册顺序执行。
Promise Resolution Procedure(解析过程)
Promise/A+规范定义了一个Promise Resolution Procedure(解析过程),用于处理then方法中onFulfilled或onRejected的返回值x,已决定返回的promise2的状态。这个过程是规范的核心,用于确保Promise的互操作性与一致性。
解析过程的步骤
-
如果
x是一个Promise:-
promise2等待x的状态:- 如果
x兑现,promise2以相同的value兑现。 - 如果
x拒绝,promise2以相同的reason拒绝。
- 如果
-
-
如果
x是一个 thenable:-
尝试调用
x.then,将其作为 Promise 处理:- 调用
x.then(onFulfilled, onRejected),并根据结果更新promise2。 - 如果调用
x.then抛出异常,promise2以该异常拒绝。
- 调用
-
-
如果
x是一个合法的JS值: -promise2以x作为value兑现。
遵循Promise/A+规范实现Promise
class MyPromise {
#state = PENDING;
#value;
#handlers = [];
constructor(executor) {
try {
executor(this.#resolve, this.#reject);
} catch (err) {
this.#reject(err);
}
}
#changeState = (state, value) => {
if (this.#state !== PENDING) {
return;
}
this.#state = state;
this.#value = value;
this.#runTasks();
}
#resolve = (data) => {
this.#changeState(FULFILLED, data);
}
#reject = (reason) => {
this.#changeState(REJECTED, reason);
}
#runTask({ onFulfilled, onRejected, resolve, reject }) {
runMicroQueue(() => {
const executor = this.#state === FULFILLED ? onFulfilled : onRejected;
if (typeof executor !== 'function') {
this.#state === FULFILLED ? resolve(this.#value) : reject(this.#value);
return;
}
try {
const result = executor(this.#value);
if (isPromise(result)) {
result.then(resolve, reject);
return;
}
resolve(result)
} catch (err) {
reject(err);
}
});
}
#runTasks = () => {
if (this.#state === PENDING) {
return;
}
while(this.#handlers[0]) {
this.#runTask(this.#handlers[0]);
this.#handlers.shift();
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this.#handlers.push({
onFulfilled,
onRejected,
resolve,
reject
});
this.#runTasks();
});
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(onSettled) {
return this.then((data) => {
onSettled();
return data;
}, (reason) => {
onSettled();
throw Error(reason);
});
}
}