本文已参与「新人创作礼」活动,一起开启掘金创作之路。 自 es6 推出
promise以来,promise强大的异步处理功能被广大开发者认可并广泛使用,那么其实现逻辑真的都非常清楚吗?这里我断断续续花了几天的时间将Promises/A+规范结合自己的一丝丝理解和实践做了翻译,方便大家更加容易的来理解promise的真实情况。 Promises/A+原文
1. Terminology(术语)
1.1. “promise” is an object or function with a then method whose behavior conforms to this specification.
1.1. promise 是一个拥有
then方法的对象或者函数,其行为准守此规范
1.2. thenable” is an object or function that defines a then method.
1.2. thenable 是一个定义
then方法的对象或者函数
1.3. “value” is any legal JavaScript value (including undefined, a thenable, or a promise).
1.3. value 任意合法类型的JavaScript值(包括
undefined, ”thenabel“ 或者 ”promise“)
1.4. “exception” is a value that is thrown using the throw statement.
1.4. exception 是由
throw抛出的异常信息
1.5. “reason” is a value that indicates why a promise was rejected.
1.5. reason 是 promise 拒绝的标识值(拒因)
2. Requirements(需求)
2.1. Promise States
A promise must be in one of three states: pending, fulfilled, or rejected.
一个
promise对象必须处于pending、fulfilled、rejected三个状态之一
2.1.1. When pending, a promise:
2.1.1. 当一个promise对象处于
pending状态:
2.1.1.1. may transition to either the fulfilled or rejected state.
2.1.1.1. 只能转变为
fulfilled或者rejected状态
2.1.2. When fulfilled, a promise:
2.1.2. 当一个promise对象处于
fulfilled状态:
2.1.2.1. must not transition to any other state.
2.1.2.1. 不能转变为任何状态
2.1.2.1. must have a value, which must not change.
2.1.2.1. 必须有一个不可变的值
2.1.3. When rejected, a promise:
2.1.3. 当一个promise对象处于
rejected状态:
2.1.3.1. must not transition to any other state.
2.1.3.1. 不能转变为任何状态
2.1.3.2. must have a reason, which must not change.
2.1.3.2. 必须有一个不可变的据因
Here, “must not change” means immutable identity (i.e. ===), but does not imply deep immutability.
这里的不可变是指的可以恒等(也就是可以用
===判断),不是深层次的不可变译者注:所谓非深层次是指比如是一个对象而非一个值,其地址不变即可,内部属性可以不受限制,比如:
let a = {a:1};
let b = a;
b.b = 2;
console.log(a === b) // true
2.2. The then Method( then 方法)
A promise must provide a then method to access its current or eventual value or reason.
一个
promise对象必须要有一个then方法来访问它的当前值、最终值或者据因。
A promise’s then method accepts two arguments:
promise的then方法可以接受两个参数:
promise.then(onFulfilled, onRejected)
2.2.1. Both onFulfilled and onRejected are optional arguments:
2.2.1.
onFulfilled和onRejected都是可选的参数:
2.2.1.1. If onFulfilled is not a function, it must be ignored.
2.2.1.1. 如果
onFulfilled不是一个函数, 它必须被忽略。
2.2.1.2. If onRejected is not a function, it must be ignored.
2.2.1.2. 如果
onRejected不是一个函数, 它必须被忽略。
2.2.2. If onFulfilled is a function:
如果
onFulfilled是一个函数:
2.2.2.1. it must be called after promise is fulfilled, with promise’s value as its first argument.
2.2.2.1. 它必须在
promise变为fulfilled状态后调用,且以promise的值(value) 作为第一个参数。
2.2.2.2. it must not be called before promise is fulfilled.
2.2.2.2. 它绝对不能在
promise变为fulfilled状态之前被调用。
2.2.2.3. it must not be called more than once.
2.2.2.3. 它至多只能被调用一次。
2.2.3. If onRejected is a function,
如果
onRejected是一个函数
2.2.3.1. it must be called after promise is rejected, with promise’s reason as its first argument.
2.2.3.1. 它必须在
promise变为rejected状态后调用,且以promise的 拒因(reason)作为第一个参数
2.2.3.2. it must not be called before promise is rejected.
2.2.3.2. 它绝对不能在
promise变为rejected状态之前被调用。
2.2.3.3. it must not be called more than once.
2.2.3.3. 它至多只能被调用一次。
2.2.4. onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
onFulfilled或者onRejected必须在上下文执行队列只包含平台代码时才被调用。译者注:
onFulfilled或者onRejected都是作为微任务,在任务队列中不存在同步逻辑任务时才会被调用
2.2.5. onFulfilled and onRejected must be called as functions (i.e. with no this value). [3.2]
2.2.5.
onFulfilled和onRejected必须作为函数直接调用(也就是不使用this调用)。
2.2.6. then may be called multiple times on the same promise.
2.2.6.
then可能被同一个promise对象调用多次。
2.2.6.1. If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.
2.2.6.1. 如果
promise处于fulfilled状态,所有从then收到的onFulfilled回调函数必须按顺序被调用。
2.2.6.2. If/when promise is rejected, all respective onRejected callbacks must execute in the order of their originating calls to then.
2.2.6.2. 如果
promise处于rejected状态,所有从then收到的onRejected回调函数必须按顺序被调用。
2.2.7. then must return a promise [3.3].
2.2.7.
then必须返回一个promise对象。
promise2 = promise1.then(onFulfilled, onRejected);
2.2.7.1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
2.2.7.1. 如果
onFulfilled或者onRejected返回一个x值,则执行下面的Promise处理过程。
2.2.7.2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
2.2.7.2. 如果
onFulfilled或者onRejected抛出一个异常e,promise2必须拒绝执行并将e作为拒因。
2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.
2.2.7.3. 如果
onFulfilled不是函数,且promise1成功执行返回一个值,promise2也必将成功执行且返回和promise1成功返回的相同的值
2.2.7.4. If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.
2.2.7.4. 如果
onRejected不是函数,且promise1拒绝执行,promise2也必将拒绝执行且返回和promise1相同的拒因
2.3. The Promise Resolution Procedure(Promise处理过程)
The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as [[Resolve]](promise, x). If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that x behaves at least somewhat like a promise. Otherwise, it fulfills promise with the value x.
promise的处理过程是一个抽象操作,将一个
promise和value作为输入,我们可以视为[[Resolve]](promise, x)。如果x是一个"thenable"(可以调用then方法的对象),其使用方式像一个promise对象,则将尝试将x的状态赋给promise,否则将以x的值来执行promise。
This treatment of thenables allows promise implementations to interoperate, as long as they expose a Promises/A+-compliant then method. It also allows Promises/A+ implementations to “assimilate” nonconformant implementations with reasonable then methods.
对"thenables"的处理方式允许
promise来进行交互操作,只要它们暴露出符合Promises/A+规范的then方法,这也使得符合Promises/A+规范的实现与不太符合规范的then实现有一定兼容性。
To run [[Resolve]](promise, x), perform the following steps:
[[Resolve]](promise, x)按以下步骤运行:
2.3.1. If promise and x refer to the same object, reject promise with a TypeError as the reason.
2.3.1. 如果
promise和x指向同一个对象,promise将拒绝执行且抛出一个TypeError作为拒因。
2.3.2. If x is a promise, adopt its state [3.4]:
2.3.2. 如果
x是一个promise对象。接收它的状态:
2.3.2.1. If x is pending, promise must remain pending until x is fulfilled or rejected.
2.3.2.1. 如果
x处于 pending 状态,则必须保留其 pending 状态至x变为fulfilled 或者 rejected。
2.3.2.2. If/when x is fulfilled, fulfill promise with the same value.
2.3.2.2. 如果
x是 fulfilled 状态,则以x的值;来执行promise。
2.3.2.3. If/when x is rejected, reject promise with the same reason.
2.3.2.3. 如果
x是 rejected 状态,则以x的拒因来拒绝执行promise。
2.3.3. Otherwise, if x is an object or function,
2.3.3. 否则,如果
x是一个对象或者函数,
2.3.3.1. Let then be x.then. [3.5]
2.3.3.1. 定义一个
then变量将x.then赋值给变量then。
2.3.3.2. If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.
2.3.3.2. 如果
x.then取值时抛出异常e,则拒绝执行promise并以e作为拒因。
2.3.3.3. If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where:
2.3.3.3. 如果
then是一个函数,用x代替this来调用它,resolvePromise作为第一个参数,rejectPromise作为第二个参数。
2.3.3.3.1. If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).
2.3.3.3.1. 如果
resolvePromise以值y为参数被调用,则运行[[Resolve]](promise, y)。
2.3.3.3.2. If/when rejectPromise is called with a reason r, reject promise with r.
如果
rejectPromise以拒因r为参数被调用,则以r为拒因拒绝执行promise。
2.3.3.3.3. If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
2.3.3.3.3. 如果
resolvePromise和rejectPromise都被调用,或者以相同的参数被调用多次,则只执行第一次调用,其他调用被忽略。
2.3.3.3.4. If calling then throws an exception e,
2.3.3.3.4. 如果调动
then方法抛出异常e,
2.3.3.3.4.1. If resolvePromise or rejectPromise have been called, ignore it.
2.3.3.3.4.1. 忽略
resolvePromise或者rejectPromise的调用。
2.3.3.3.4.2. Otherwise, reject promise with e as the reason.
2.3.3.3.4.2. 除此之外,拒绝执行
promise并以e作为拒因
2.3.3.4. If then is not a function, fulfill promise with x.
2.3.3.4. 如果
then不是一个函数,则以x为值执行promise
2.3.4. If x is not an object or function, fulfill promise with x.
2.3.4. 如果
x不是一个对象或者函数,,则以x为值执行promise
If a promise is resolved with a thenable that participates in a circular thenable chain, such that the recursive nature of [[Resolve]](promise, thenable) eventually causes [[Resolve]](promise, thenable) to be called again, following the above algorithm will lead to infinite recursion. Implementations are encouraged, but not required, to detect such recursion and reject promise with an informative TypeError as the reason. [3.6]
如果一个
promise在一个循环的 thenable 链中被执行,例如递归性执行[[Resolve]](promise, thenable)又使得其被再次调用,根据上述的算法将会陷入无限递归之中。算法虽不强制要求,但也鼓励施者检测这样的递归是否存在,若检测到存在则以一个可识别的TypeError为据因来拒绝promise
3. Notes(注释)
3.1. Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfille and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.
3.1. 这里"平台代码"是指引擎、执行环境、和
promise执行代码。在实践中,这个这个约束条件保证onFulfille和onRejected是异步执行的,且是在then被调用的event loop执行队列之后新的执行队列中执行。这个可以借助于macro-task宏任务就像:setTimeout或者setImmediate,或者micro-task微任务就像MutationObserver或者process.nextTick。由于promise的执行被认为是平台代码,它自身在处理在处理程序时可能已经包含一个任务调度队列。
3.2.
That is, in strict mode this will be undefined inside of them; in sloppy mode, it will be the global object.
3.2.
this在严格模式下将是undefined,在非严格模式下,将是全局对象。
3.3. Implementations may allow promise2 === promise1, provided the implementation meets all requirements. Each implementation should document whether it can produce promise2 === promise1 and under what conditions.
3.3. 代码实现在满足所有要求的情况下可以允许
promise2 === promise1。每个实现都要文档说明其是否允许以及在何种条件下允许promise2 === promise1。
3.4. Generally, it will only be known that x is a true promise if it comes from the current implementation. This clause allows the use of implementation-specific means to adopt the state of known-conformant promises.
3.4. 事实上
x是否来自于正确的实现才决定其是否为一个正确的promise。这一规则允许那些特例实现接受符合已知要求的promises状态。
3.5. This procedure of first storing a reference to x.then, then testing that reference, and then calling that reference, avoids multiple accesses to the x.then property. Such precautions are important for ensuring consistency in the face of an accessor property, whose value could change between retrievals.
3.5. 这步我们先是存储了一个指向
x.then的引用,然后测试并调用该引用,以避免多次访问x.then属性。这种预防措施确保了该属性的一致性,因为其值可能在检索调用时被改变。
3.6. Implementations should not set arbitrary limits on the depth of thenable chains, and assume that beyond that arbitrary limit the recursion will be infinite. Only true cycles should lead to a TypeError; if an infinite chain of distinct thenables is encountered, recursing forever is the correct behavior.
实现方案不应该对
then调用链的深度做限制,并且认为超出设置限制继续递归调用就是无限循环。只有当真正的环形调用才会导致TypeError;如果明确的截然不同的then调用链,那么无限执行下去是正确的。