"不畏惧,不将就,未来的日子好好努力"——大家好!我是小芝麻😄
思维导图
一个开放、健全且通用的 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 均不相同,那么递归下去永远是正确的行为。