什么是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