Promises
Promise
表示一个异步操作的最终结果,与之进行交互的方式主要是 then 方法,该方法注册了两个回调函数,用于接收 promise 的终值或本 promise 不能执行的原因。
一个 Promise有以下几种状态:
pending:
初始状态,既不是成功,也不是失败状态。fulfilled:
意味着操作成功完成。rejected:
意味着操作失败。
Promise
本质是一个状态机。每个promise
只能是 3 种状态中的一种:pending、fulfilled
或rejected
。状态转变只能是pending -> fulfilled
或者pending -> rejected
。状态转变不可逆。then
方法可以被同一个promise
调用多次。then
方法必须返回一个promise
。规范里没有明确说明返回一个新的 promise 还是复用老的promise
(即 return this),大多数实现都是返回一个新的promise
,而且复用老的promise
可能改变内部状态,这与规范也是相违背的。- 值穿透(上一个
promise
传递过来的值,经由这个then
方法的时候不做任何处理,而是交给再下个then
方法去处理)。
注意: 如果一个promise
对象处在fulfilled
或rejected
状态而不是pending
状态,那么它也可以被称为settled
状态。你可能也会听到一个术语resolved
,它表示promise
对象处于fulfilled
状态。
术语集
Promises
:Promise
规范自身promise
对象:promise
对象指的是Promise
实例对象ES6 Promises
:如果想明确表示使用ECMAScript 6th Edition
的话,可以使用ES6
作为前缀(prefix
)Promises/A+
:这是ES6 Promises
的前身,是一个社区规范,它和ES6 Promises
有很多共通的内容。Thenable
:类Promise
对象。 拥有名为.then
方法的对象。promise chain
:指使用then
或者catch
方法将promise
对象连接起来的行为。 此用语只是在本书中的说法,而不是在ES6 Promises
中定义的官方用语。
Promise
的实现类库
如果说一个类库兼容 Promises/A+
的话,那么就是说它除了具有标准的 then
方法之外,很多情况下也说明此类库还支持 Promise.all
和 catch
等功能。
但是 Promises/A+
实际上只是定义了关于 Promise#then
的规范,所以有些类库可能实现了其它诸如 all
或 catch
等功能,但是可能名字却不一样。
如果我们说一个类库具有 then
兼容性的话,实际上指的是 Thenable
,它通过使用 Promise.resolve
基于ES6 Promise
的规定,进行promise
对象的变换。
语法
1 | new Promise( function(resolve, reject) {...} /* executor */ ); |
Promise
带有 resolve
和 reject
两个参数的函数;
resolve
和 reject
函数被调用时,分别将 promise
的状态改为fulfilled
(完成)或 rejected
(失败)
属性
Promise.length
:length
属性,其值总是为 1 (构造器参数的数目).Promise.prototype
:表示Promise
构造器的原型.
方法
Promise.all(iterable)
:这个方法返回一个新的promise
对象,该promise
对象在iterable
参数对象里所有的promise
对象都成功的时候才会触发成功,一旦有任何一个iterable
里面的promise
对象失败则立即触发该promise
对象的失败。这个新的
promise
对象在触发成功状态以后,会把一个包含iterable
里所有promise
返回值的数组作为成功回调的返回值,顺序跟iterable
的顺序保持一致;如果这个新的
promise
对象触发了失败状态,它会把iterable
里第一个触发失败的promise
对象的错误信息作为它的失败错误信息Promise.all
方法常被用于处理多个promise
对象的状态集合Promise.race(iterable)
:当iterable
参数里的任意一个子promise
被成功或失败后,父promise
马上也会用子promise
的成功返回值或失败详情作为参数调用父promise
绑定的相应句柄,并返回该promise
对象Promise.reject(reason)
:返回一个状态为失败的Promise
对象,并将给定的失败信息传递给对应的处理方法Promise.resolve(value)
:返回一个状态由给定value
决定的Promise
对象如果该值是一个
Promise
对象,则直接返回该对象;如果该值是
thenable
(即,带有then
方法的对象),返回的Promise
对象的最终状态由then
方法执行决定;否则的话(该
value
为空,基本类型或者不带then
方法的对象),返回的Promise
对象状态为fulfilled
,并且将该value
传递给对应的then
方法如果你不知道一个值是否是
Promise
对象,使用Promise.resolve(value)
来返回一个Promise
对象,这样就能将该value
以Promise
对象形式使用。
Promise
原型
Promise.prototype.constructor
返回被创建的实例函数. 默认为 Promise
函数.
Promise.prototype.catch(onRejected)
添加一个拒绝(rejection
) 回调到当前 promise
, 返回一个新的 promise
当这个回调函数被调用,新 promise
将以它的返回值来resolve
;
否则如果当前promise
进入fulfilled
状态,则以当前promise
的完成结果作为新promise
的完成结果.
Promise.prototype.then(onFulfilled, onRejected)
添加解决(fulfillment
)和拒绝(rejection
)回调到当前 promise
, 返回一个新的 promise
, 将以回调的返回值来 resolve
.
Promise.prototype.finally(onFinally)
添加一个事件处理回调于当前promise
对象,并且在原promise
对象解析完毕后,返回一个新的promise
对象
回调会在当前promise
运行完毕后被调用,无论当前promise
的状态是完成(fulfilled
)还是失败(rejected
)
承诺源码
代码片段1
此处的PromiseA
等同于Promise
1 | var promise = new PromiseA(function(resolve, reject) { |
结果:
then
方法可以被同一个 promise
调用多次
代码片段 all
与 race
1 | var p1 = new PromiseA(function(resolve, reject) { |
结果:
1 | race 大爷 |
源码代码
1 | ; |
参考注释
- 平台代码指的是引擎、环境以及
promise
的实施代码。实践中要确保onFulfilled
和onRejected
方法异步执行,且应该在then
方法被调用的那一轮事件循环之后的新执行栈中执行。这个事件队列可以采用“宏任务(macro-task
)”机制或者“微任务(micro-task
)”机制来实现。由于promise
的实施代码本身就是平台代码(译者注:即都是JavaScript
),故代码自身在处理在处理程序时可能已经包含一个任务调度队列。
macrotask
和 microtask
两个概念,这表示异步任务的两种分类。在挂起任务时,JS
引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue
)中取出第一个任务,执行完毕后取出 microtask
队列中的所有任务顺序执行;之后再取 macrotask
任务,周而复始,直至两个队列的任务都取完。
两个类别的具体分类如下:
macro-task:
script(整体代码),setTimeout
,setInterval
,setImmediate
,I/O
,UI rendering
micro-task:
process.nextTick
,Promises
(这里指浏览器实现的原生Promise
),Object.observe
,MutationObserver