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 renderingmicro-task:process.nextTick,Promises(这里指浏览器实现的原生Promise),Object.observe,MutationObserver