什么是Promise
Promise的核心理念是一个异步操作的结果,Promise包含两部分
[[PromiseStates]][[PromiseValue]]
Promise状态三种可能:
pending: 悬而未决resolved: 决定rejected: 拒绝
异步性
1 | const p = new Promise((resolve, reject) => { |
Promise的then()具有异步性,当执行到.then()部分,这部分会自动进入到Promise的异步事件队列,不会阻塞同步代码的执行,所以Called first?先输出。
输出结果
1 | Called first ? |
立即执行性
1 | const p = new Promise((resolve, reject) => { |
从Promise的异步性,我们可以推断出,After new Promise,会先于then()方法中的输出。同时Promise的立即执行性,定义了promise定义的同时就会立即执行,并不依赖于then()的调用。而且与函数明显不同,函数需要主动调用才会执行。
输出结果
1 | Create a promise |
Promise的状态
1 | const p1 = new Promise((resolve, reject) => { |
当Promise创建完成时,处于 pending 状态;
当Promise执行了resolve方法,Promise对象的状态会变成 resolved 状态;
当Promise执行了reject方法,Promise对象的状态会变成 rejected 状态;
先输出
1 | Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1} |
然后输出
1 | p1-then: 1 |
500ms之后,p2和p3的Promise状态被执行,then被触发,输出:1
2p2-then: 2
p3-catch 3
最后会输出:
1 | p2-setTimeout: Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 2} |
状态不可逆性
1 | const p1 = new Promise((resolve, reject) => { |
Promise一旦变成resolved或是rejected,这个状态就不能再次变化,这就是Promise的不可逆性。
输出
1 | p1 success 1 |
链式调用
1 | const p = new Promise(((resolve, reject) => { |
Jquery对象链式调用是执行jquery方法之后,会继续返回jquery对象;类似这个原理,Promise对象的then方法会返回一个新的Promise对象,这样就可以继续调用then方法。同样then方法中的两个参数还是fulfilled对象和rejected对象。
当return一个值或者Promise.resolve()时,状态为 resolved
当throw一个异常或者return Promise.reject(),状态为 rejected
注: 当then()方法中没有return时,会默认返回undefined,状态为 resolved
输出
1 | 1 |
Promise中的异常处理
1 | const p1 = new Promise((resolve, reject) => { |
Promise中的异常会交给then方法中的第二个回调函数处理,一旦处理完成,会继续返回一个Promise对象给后续then方法。
可以看到输出是p1和p2交替输出的,这个并不一定是交替输出,取决于执行情况,也可能是p2先输出。
输出
1 | p1 then err: ReferenceError: foo is not defined |
Promise.resolve()
Promise.resolve()语法:
1 | Promise.resolve(value); |
value: 用来解析待返回promise对象的参数,既可以是一个promise对象,也可以是一个thenable(即带有then方法)。
1 | const p1 = Promise.resolve(1); |
p1: 接收了一个普通值1,所以会返回一个resolved状态的Promise对象,并且值为1。p2: 接收了一个promise对象p1,会直接返回这个promise对象。p3和p4: 通过new方式创建了一个新的promise对象。
所以,p1 === p2,p3和p4都是创建的新对象,所以自身和其他三个对象都不相等。
输出
1
2
3
4 true
false
false
false
但是后三个输出是:
1 | p2 = 1 |
很有意思的是,明明是p4先执行的then方法,但是却是后输出的。
在定义完4个promise对象时,状态分别为:1
2
3
4Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1}
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1}
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1}
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
很明显,p4是pending状态,与其他三个不同,因为p4的resolve中接收的参数是一个promise对象p1,resolve会对p1进行“拆箱”操作,这个过程是异步的。
注:把基本数据类型转换为对应的引用类型的操作称为装箱,把引用类型转换为基本的数据类型称为拆箱。
resolve() & reject() 的区别
1 | const p1 = new Promise((resolve, reject) => { |
resolve方法和reject方法除了在状态上有区别,处理方式上也有区别,resolve方法上面提到了会对promise对象“拆箱”,但是reject方法不会。
p3没有“拆箱”操作,所以会最先输出,直接调用reject方法,输出Promise.resolve('resolve')对象p1会“拆箱”得到Promise.resolve('resolve')这个promise对象的状态和值,调用resolve方法。p2会“拆箱”得到Promise.reject('reject')这个promise对象的状态和值,因为得到的状态是rejected,所以会调用reject方法。
输出
1 | p3-reject: Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: "resolve"} |
all() & race() & then() 区别
Promise.all()语法:
1 | Promise.all(iterable); |
Promise.race()语法:
1 | Promise.race(iterable) |
iterable: 可迭代对象,例如一个数组。
1 | let timerPromisefy = (delay) => { |
Promise.all()方法返回一个Promise,当iterable参数中的 promise 并行执行,当所有 promise 都已经 resolve 了,返回 resolved 状态。当传递的 promise 包含一个 reject ,则返回 rejected 状态。
如果Promise.all()返回 resolved , 那么执行时间取决于执行最最慢的那个 promise;如果Promise.all()返回 rejected , 执行时间取决于第一个返回 rejected 的执行时间。
Promise.race()方法返回一个Promise,当iterable参数中只要有一个 promise 状态被判定了,那么就返回该状态。
所以Promise.race()的执行时间取决于执行最快的那个 promise。
Promise.then()方法的执行时间,是每个链式调用总时间之和。
输出
1
2
3 Promise race: 2.3232421875ms
Promise all: 3.675048828125ms
Promise then: 31.32373046875ms