“不畏惧,不将就,未来的日子好好努力”——大家好!我是小芝麻?
一个开放、健全且通用的 JavaScript Promise 标准。——由开发者制定,供开发者参考
Promise
表示异步操作的最终结果,与它进行交互的主要方式是 then
方法,该方法注册了两个回调函数用来接收 Promise
成功的结果或 Promise
不能执行的原因。
本规范详细说明了 then
方法的执行过程,所有遵循 Promises/A+
规范实现的 promise
均可把本标准作为基础。因此,本规范是非常稳定的。尽管 Promises/A+
组织可能偶尔会对本规范进行一些小的向后兼容的改动,主要是为了处理一些特殊的极端情况,如果我们要进行大规模不兼容的更新,我们一定会在事先进行谨慎地考虑、详尽的探讨和严格的测试。
从历史上看,本规范实际上是把之前 Promise/A 规范 中的建议明确成为了行为标准:我们一方面扩展了原有规范约定俗成的行为,一方面删减了原规范的一些特例情况和有问题的部分。
最后,核心的 Promises/A+ 规范不设计如何创建(create)、实现(fulfill)和拒绝(reject) promise,而是专注于提供一个通用的 then
方法。上述对于 promises 的操作方法将来在其他规范中可能会提及。
1. 术语
1.1. promise
是一个对象或者函数,并且拥有符合本规范的 then
方法。
1.2. thenable
是定义 then
方法的对象或者函数。
1.3. value
是任意合法的 JavaScript 值,(包括 undefined,thenable,promise)
1.4 exception
是使用throw
语句抛出的值
1.5 reason
表示一个promise
被拒绝的原因。
2. 要求
2.1. Promise 状态(states)
一个 Promise 的状态必须为以下三种状态之一:等待态(Pending) 、完成态(Fulfilled) 和 拒绝态(Rejected) 。
-
2.1.1. 当 promise 是准备态(Pending) 时
- 2.1.1.1. 可以改变为 完成态(Fulfilled)或者 拒接态(Rejected)
-
2.1.2 当 promise 是 完成态(Fulfilled) 时
-
2.1.2.1 promise 不能改变为其他状态
-
2.1.2.2 必须有一个 值(value) ,并且不能改变
-
-
2.1.3 当 promise 是 拒接态(Rejected) 时
-
2.1.3.1 promise 不能改变为其他状态
-
2.1.3.2 必须有一个 原因(reason) , 并且不能改变
-
这里的不能改变指的是恒等(即可用 ===
判断相等),而不是意味着更深层次的不能改变(指当 value 或 reason 不是基本值时,只要求其引用地址相等,但属性值可被更改)
2.2. then
方法
一个 promise
必须提供一个 then
方法来接收它当前 完成的值(value) 或者 拒绝的原因(reason)
每一个 promise
的 then
方法 都接收 两个参数:
promise.then(onFulfilled, onRejected)
复制代码
-
2.2.1.
onFulfilled
和onRejected
都是可选参数:-
2.2.1.1 如果
onFulfilled
不是函数,则必须忽略 -
2.2.1.2 如果
onRejected
不是函数,则必须忽略
-
-
2.2.2. 如果
onFulfilled
是一个函数:-
2.2.2.1 此函数必须在
promise
完成(Fulfilled)后被调用,以promise
的值(value)作为它的第一个参数 -
2.2.2.2 此函数在
promise
完成(Fulfilled)之前一定不能被调用 -
2.2.2.3 此函数只能被调用一次
-
-
2.2.3. 如果
onRejected
是一个函数:-
2.2.3.1 此函数必须在
promise
拒绝(Rejected)后被调用,以promise
拒绝的原因(reason)作为它的第一个参数 -
2.2.3.2 此函数在
promise
拒绝(Rejected)之前一定不能被调用 -
2.2.3.3 此函数只能被调用一次
-
-
2.2.4. 在执行上下文堆栈仅包含平台代码之前,不得调用
onFulfilled
和onRejected
[注释3.1] -
2.2.5.
onFulfilled
和onRejected
必须被作为函数调用(即 没有this
值)[注释3.2] -
2.2.6.
then
方法可以在同一个promise
里调用多次-
2.2.6.1 如果/当
promise
完成(Fulfilled)时,所有相应的onFulfilled
回调必须按照then
的顺序依次执行。 -
2.2.6.2 如果/当
promise
拒绝(Rejected)时,所有相应的onRejected
回调必须按照then
的顺序依次执行。
-
-
2.2.7.
then
方法必须返回一个promise
[注释3.3]promise2 = promise1.then(onFulfilled, onRejected); 复制代码
-
2.2.7.1 如果
onFulfilled
或onRejected
返回一个值x
,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)
[注释2.3] -
2.2.7.2 如果
onFulfilled
或者onRejected
抛出一个异常e
,则promise2
必须拒绝(Rejected),并返回异常e
的原因(reason) -
2.2.7.3 如果
onFulfilled
不是函数且promise1
完成(Fulfilled)执行,promise2
必须完成(Fulfilled)执行,并返回和promise1
相同的值(value) -
2.2.7.4 如果
onRejected
不是函数且peomise1
是拒绝(Rejected)状态,promise2
也必须拒绝(Rejected),并返回和promise1
相同的原因(reason)
-
2.3. Promise 解决过程
Promise 解决过程 是一个抽象的操作,其需输入一个 promise
和一个值(value),我们表示为 [[Resolve]](promise, x)
,如果 x
有 then
方法且看上去像一个 Promise ,解决程序即尝试使 promise
接受 x
的状态;否则其用 x
的值来执行 promise
。
这种 thenable 的特性使得 Promise 的实现更具有通用性:只要其暴露出一个遵循 Promise/A+ 协议的 then
方法即可;这同时也使遵循 Promise/A+ 规范的实现可以与那些不太规范但可用的实现能良好共存。
运行 [[Resolve]](promise, x)
需遵循以下步骤:
-
2.3.1. 如果
promise
和x
指向同一对象,以TypeError
为原因拒绝执行promise
-
2.3.2. 如果
x
是一个promise
, 那么就采用他的状态[注释3.4]:-
2.3.2.1 如果
x
处于等待态(pending),promise
需保持为等待态(pending)直至x
为完成态(Fulfilled)或拒绝(Rejected) -
2.3.2.2 如果
x
处于完成态(Fulfilled),用相同的值(value)完成(Fulfill)promise
-
2.3.2.3 如果
x
处于拒绝态(Rejected),用相同的原因(reason)拒绝(reject)promise
-
-
2.3.3. 另外,如果
x
是对象或者函数-
2.3.3.1. 把
x.then
赋值给then
[注释3.5] -
2.3.3.2. 如果取
x.then
的值时抛出错误e
,则以e
为原因(reason)拒绝(reject)promise
-
2.3.3.3. 如果
then
是一个函数,那么把x
当做this
调用它,第一个参数resolvePromise
,第二个参数rejectPromise
,其中:-
2.3.3.3.1 如果使用值(value)
y
为参数来调用resolvePromise
,则运行[[Resolve]](promise, y)
-
2.3.3.3.2 如果调用
rejectPromise
的参数是原因(reason)是r
时,则使用原因(reason)r
来拒绝(reject)promise
-
2.3.3.3.3 如果
resolvePromise
和rejectPromise
同时被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用 -
2.3.3.3.4 如果调用
then
抛出了异常e,-
2.3.3.3.4.1 如果已经调用了
resolvePromise
或rejectPromise
,则忽略。 -
2.3.3.3.4.2 否则,以
e
为原因reason
拒绝(reject)promise
-
-
-
2.3.3.4. 如果
then
不是一个函数,则以x
为参数完成(fulfill)promise
-
-
2.3.4. 如果
x
不为对象或者函数,以x
为参数完成(fulfill)promise
如果一个 promise
是用一个参与循环 thenable
链的 thenable
来解析的,那么 [[Resolve]](promise,thenable)
的递归性质最终会导致再次调用 [[Resolve]](promise,thenable)
,遵循上述算法将导致无限递归。我们鼓励但不要求实现检测这种递归,并以 TypeError
错误为理由(reason)拒绝(reject) promise
3. 注释
3.1. 这里的 “平台代码“ 指的是引擎、环境和 promise
实现代码。在实践中,该要求确保在调用 then
方法被调用的那一轮的事件循环之后,使用新堆栈异步执行 onFulfilled
和 onRejected
。这可以通过“宏任务”机制(如setTimeout 或 setImmediate )或“微任务”机制(如 MutationObserver 或 process.nextTick )实现。由于 promise
实现被认为是平台代码(注: 即都是 JavaScript),因此它本身可能包含一个任务调度队列或调用处理程序的“trampoline”。
3.2. 也就是说在 严格模式(strict) 中,函数 this
的值为 undefined
;在非严格模式中其为全局对象。
3.3. 代码实现在满足所有要求的情况下,可以允许 promise2 === promise1
。每个实现都要文档说明其是否允许以及在何种条件下允许 promise2 === promise1
。
3.4. 总体来说,如果 x
符合当前实现,我们才认为它是真正的 promise
。本规则允许那些特例实现接受符合已知要求的 Promises
状态。
3.5. 这步我们先是存储了一个指向 x.then
的引用,然后测试并调用该引用,以避免多次访问 x.then
属性。这种预防措施确保了该属性的一致性,因为其值可能在检索调用时被改变。
3.6 实现不应该对 thenable
链的深度设限,并假定超出本限制的递归就是无限循环。只有真正的循环递归才应能导致 TypeError
异常;如果一条无限长的链上 thenable
均不相同,那么递归下去永远是正确的行为。