一个 promise 表示一个异步操作的最终结果。和 promise 交互的主要方式是通过它的 then 方法,通过在 then 方法中注册回调函数来接收 promise 的最终值或者无法实现的原因(拒因)。
本规范详尽描述了 then 方法的行为,为所有 Promises/A+ 的实现提供了一个可交互的基础。因此,该规范将是非常稳定的。尽管 Promises/A+ 组织 可能会偶尔通过修正(向后兼容的 minor 版本)该规范来解决一些新发现的边界情况。只有经过仔细的考虑、讨论和测试之后,我们才会整合出一个大的或向后不兼容的版本。
Promises/A+ 标准
一个可靠的、可交互的 JavaScript Promises 开放标准 ——供实现者参考
一个 promise 表示一个异步操作的最终结果。和 promise 交互的主要方式是通过它的 then 方法,通过在 then 方法中注册回调函数来接收 promise 的最终值或者无法实现的原因(拒因)。
本规范详尽描述了 then 方法的行为,为所有 Promises/A+ 的实现提供了一个可交互的基础。因此,该规范将是非常稳定的。尽管 Promises/A+ 组织 可能会偶尔通过修正(向后兼容的 minor 版本)该规范来解决一些新发现的边界情况。只有经过仔细的考虑、讨论和测试之后,我们才会整合出一个大的或向后不兼容的版本。
Promises/A+ 澄清了早期的 Promises/A 提案的行为条款,扩展了一些内容并省略了未明确说明或有问题的部分。
最后,核心的 Promises/A+ 规范不涉及如何
create(创建)
、fulfill(履行)
、reject(拒绝)
promises,而是选择专注于提供一种可交互的 then 方法。未来在配套规范中的工作可能会涉及这些主题。1. 名词解释
then
方法的object
或者function
。then
方法的object
或者function
。undefined
,thenable
或者promise
)throw
语句抛出的值。promise
的原因。2. 要求
2.1 Promise 状态
一个
promise
的状态必须是pending
、fulfilled
、rejected
三种状态中的一种。2.1.1 当
promise
处于pending
状态时:promise
可以转变为fulfilled
或者rejected
状态。2.1.2 当
promise
处于fulfilled
状态时:promise
禁止转变为其他状态。2.1.3 当
promise
处于rejected
状态时:promise
禁止转变为其他状态。注意:不可变 意味着恒等(即
===
),但不意味着深度不可变。2.2
then
方法一个
promise
必须提供一种方法来访问其当前的最终值或者拒因。一个
promise
的then
方法接收两个参数:2.2.1
onFulfilled
和onRejected
都是可选参数:onFulfilled
不是一个函数,则必须忽略掉。onRejected
不是一个函数,则必须忽略掉。2.2.2 如果
onFulfilled
是一个函数:promise
的状态为fulfilled
时被调用,并且第一个参数是promise
的终值promise
状态为fulfilled
之前被调用2.2.3 如果
onRejected
是一个函数:promise
的状态为rejected
时被调用,并且第一个参数是promise
的拒因promise
状态为rejected
之前被调用2.2.4
onFulfilled
和onRejected
只允许执行上下文堆栈包含平台代码时才可以被调用。[3.1]2.2.5
onFulfilled
和onRejected
必须被作为函数调用(即没有this
值)。[3.2]2.2.6
then
可以被同一个promise
调用多次。promise
为fulfilled
状态时,所有接收到的onFulfilled
回调函数必须按照其调用then
的顺序执行。promise
为rejected
状态时,所有接收到的onRejected
回调函数必须按照其调用then
的顺序执行。2.2.7
then
方法必须返回一个promise
。[3.3]onFulfilled
或者onRejected
返回了一个值x
,则执行 Promise 决策程序[[Resolve]](promise2, x)
onFulfilled
或者onRejected
返回了一个异常e
,则promise2
必须转化为rejected
状态并以e
作为拒因。onFulfilled
不是一个函数并且promise1
是fulfilled
状态,则promise2
也必须是fulfilled
状态并返回相同的值(promise1
返回的值)。onRejected
不是一个函数并且promise1
是rejected
状态,则则promise2
也必须是rejected
状态并返回相同的拒因(promise1
返回的拒因)。2.3 Promise 决策程序
Promise 决策程序(promise resolution procedure) 是一个抽象的操作,将
promise
和值作为输入,用代码表示为[[Resolve]](promise, x)
。如果x
是一个thenable
,则该程序会尝试让promise
接受x
的状态,我们假设x
的行为至少像一个 promise。 否则promise
则以x
为最终值直接执行。这种对
thenable
的处理使得 promise 的实现更加灵活,只要暴露出符合Promises/A+
的规范的then
方法即可。它还允许Promises/A+
兼容不合规范的实现。运行
[[Resolve]](promise, x)
,将执行以下几种步骤:2.3.1 如果
promise
和x
引用相同的对象,则拒绝执行promise
并且以TypeError
为拒因。2.3.2 如果
x
是一个promise
,则接受它的状态[3.4]:x
处于pending
状态,则promise
则必须保持pending
状态直到x
变为fulfilled
或者rejected
状态。x
处于fulfilled
状态,则以相同的值执行promise
。x
处于rejected
状态,则以相同的拒因拒绝执行promise
。2.3.3 否则,如果
x
是一个对象或者函数,x.then
作为promise
的then
。[3.5]x.then
的过程中发生了异常e
,则以e
作为拒因拒绝执行promise
。x.then
是一个函数,则以x作为this
值调用该函数,第一个参数是resolvePromise
, 第二个参数是rejectPromise
,其中:resolvePromise
以值y
为参数被调用,则执行[[Resolve]](promise, y)
。rejectPromise
以拒因r
为参数被调用,则以r
为拒因拒绝执行promise
。resolvePromise
和rejectPromise
都被调用,或者以同样的参数调用多次,则采用第一次调用并且忽略掉其他的调用。then
方法中发生异常e
,resolvePromise
或者rejectPromise
被调用,则忽略它。e
为拒因拒绝执行promise
。x.then
不是一个函数,则以x为最终的值执行promise
。2.3.4 如果
x
不是一个对象或者函数,则以x为最终的值执行promise
。如果一个 promise 在一条 由 thenable 组成的循环链中被 resolved,则会导致
[[Resolve]](promise, thenable)
执行[[Resolve]](promise, thenable)
,造成无限循环。我们鼓励去检测由此导致的错误,并以TypeError
拒绝执行promise
,但这不是必须的。[3.6]附录
3.1
这里的
platofrm code
是指引擎、环境和promise
实现代码。实际上,这一要求确保onFulfilled
和onRejected
是异步执行,并且是在then
所被调用的那一轮的事件循环之后的新执行栈中执行。这边可以使用setTimeout
或者setImmediate
这类的宏任务(macro-task)实现或者使用MutationObserver
或process.nextTick
这类的微任务(micro-task)去实现。因为promise
的实现被认定为平台代码,他可能包含自身的任务队列。3.2
也就是说,在严格模式下,
this
值可能会是undefined
,在非严格模式下,this
指向全局对象。3.3
允许实现
promise2 === promise1
,前提是必须实现所有要求。并且每个实现都应该记录它是否会产生及在什么条件下会产生promise2 === promise1
。3.4
只有符合当前规范的
x
才能被称为真正的promise
3.5
首先存储对
x.then
的引用,然后测试该引用,然后调用该引用的过程应该避免对x.then
属性的多次访问。此类预防措施对于确保访问属性的一致性非常重要,访问属性的值可能会在检索过程中发生变化。3.6
实现不应该去设置
thenable 链
的最大长度,并且去假定调用超过了设置的最大长度就是无限循环的调用。只有真正的递归调用才会抛出TypeError
,如果thenable 链
上的每一个thenable
对象都不相同,那他就应该无限调用下去。