浅析Promise
谈到JS的异步操作,往往第一时间会想到Promise。 但是Promise是否等于异步操作呢? 答案是不。
jacascript里的异步操作是指:js引擎线程在执行到该操作时不会立即返回结果(区别于同步操作),而是将其交由其他浏览器线程进行处理,js引擎线程本身继续往下操作。 待其他现场处理完毕将回调函数放进消息队列后再由js引擎线程进行处理。
所以我们可以得出异步操作的核心特征:
- 非阻塞性,异步操作不会阻塞后续代码的执行。
- 回调函数,当一个异步操作完成后,他的回调函数会被调用。
我们在工作学习中常用到的promise不能和异步操作画等号,它实则是ES6新增的让我们更优雅简单地书写异步操作的一种方式。
Promise的三种状态
- pending:初始状态,待定结果
- resolve:操作成功
- rejected:操作失败

状态变更方法
Promise为我们提供了两个方法用于改变Promise实例的运行状态。分别是操作成功resolve()
, 操作失败reject()
resolve()
resolve()
被用来敲定一个promise的成功状态。
如果入参本身就是一个Promise或其他非Promise类型,那么会作为一个Promise被返回;
当入参是一个 thenable 对象,resolve() 将调用其 then() 方法及其两个回调函数;并根据thenable的then()
里最先敲定的状态返回一个promise。
实例:
javascript
// 传入非promise
const p1 = Promise.resolve(111);
// 传入promise
const p2 = Promise.resolve(new Promise((resolve, reject) =>
resolve(123)
));
// thenable
const p3 = Promise.resolve({
then(onFulfill, onReject) {
onFulfill("已兑现!");
},
})
// thenable
const p4 = Promise.resolve({
then(onFulfill, onReject) {
throw new TypeError("已失败")
onFulfill("已兑现!");
},
})
p1.then(val =>
console.log(val)
).catch(val =>
console.log(val)
)
p2.then(val =>
console.log(val)
).catch(val =>
console.log(val)
)
p3.then(val =>
console.log(val)
).catch(val =>
console.log(val)
)
p4.then(val =>
console.log(val)
).catch(val =>
console.log(val)
)
返回值
javascript
> 111
> 123
> "已兑现!"
> TypeError: 已失败
Promise.reject()
:
reject()
被用来敲定一个promise的失败状态。
入参为该Promise被拒绝的原因或一个promise对象。
与resolve不同的是,如果传入的是一个promise对象,resolve会返回和入参相同的promise,而reject会返回一个新的promise。
嵌套调用
需要注意的是,如果绑定相应回调函数时 Promise 已经确定了状态(在创建时就已经执行了resolve/rejected),该回调函数将被立即调用。
javascript
new Promise((resolveOuter) => {
resolveOuter(
new Promise((resolveInner) => {
setTimeout(resolveInner => {
console.log("inner end")}, 1000);
}),
);
}).then(console.log("outer end"));
返回结果
javascript
> "outer end"
> "inner end"
通过这个返回结果可以看出就算resolveOuter里新建的Promise没有执行完,但是外部Promise状态确认后里面执行了then方法里的操作。
Promise的基本结构
javascript
new Promise((resolve, rejected) => {
})
.then()
.catch()
.finally()
在基本结构里 (resolve, rejected) => {})
是一个同步任务区,该区域里的代码都是同步执行的。.then()
.catch()
分别是成功回调和失败回调,这个区域是异步执行的。.finally()
是这个promise执行完毕,无论是成功还是失败都会执行的区域,所以它是晚于.then()
和.catch()
的。
并发Promise
讲到异步执行,那我们就不得不讨论并发的情况,promise同样对并发有着很好的支持。
Promise.all() :
all()
接受一个promise数组或一个字符串,返回一个promise。若有一个promise失败,则立马结束调用并返回最先失败的promise失败原因。如果所有的promise都成功了则返回一个数组,每个元素为该promise的resolve的返回值,且数组顺序与传入顺序一致。
如果传入的数组里有非promise 值,则该值被忽略直接返回,前提是all被resolve返回。
传入的promise都resolve
javascript
const p1 = new Promise((resolve, rejected) => {
setTimeout(resolve("111"), 1000)})
const p2 = 222
const p3 = Promise.resolve(333)
const Pall = Promise.all([p1, p2, p3]).then(values =>
console.log(values)
)
返回值
javascript
[111,222,333]
传入的promise有一个reject
javascript
const p1 = new Promise((resolve, rejected) => {
setTimeout(rejected("111失败"), 1000)
})
const p2 = 222
const p3 = Promise.resolve(333)
const p4 = Promise.reject("444失败")
const Pall = Promise.all([p1, p2, p3, p4]).catch(
val => {console.log(val)}
)
返回值
javascript
"111失败"
Promise.allSettled() :
allSettled()
接受一个promise数组,无论传入的promise是否成功或者失败,都返回一个对象数组且每个对象都包含status:该promise的最终状态,value(resolve)/reason(reject)。
如果传入的数组里有非promise 值,则该值被认为直接resolve并返回。
实例
javascript
const p1 = new Promise((resolve, rejected) => {
setTimeout(rejected("111失败"), 1000)
})
const p2 = 222
const p3 = Promise.resolve(333)
const p4 = Promise.reject("444失败")
const Pall = Promise.allSettled([p1, p2, p3, p4]).then(results => {
for(const result of results){
console.log(result)
}
})
返回值
javascript
> Object { status: "rejected", reason: "111失败" }
> Object { status: "fulfilled", value: 222 }
> Object { status: "fulfilled", value: 333 }
> Object { status: "rejected", reason: "444失败" }
Promise.any() :
any()
接受一个promise数组,返回一个promise。若有一个promise成功,则立马结束调用并返回最先成功的promise返回值。如果所有的promise都失败了返回一个AggregateError报错,提示All promises were rejected。
如果传入的数组里有非promise 值,则该值被忽略并直接视为resolve。传入空数组时any()
会视为直接失败。
传入的promise有resolve时
javascript
const p1 = new Promise((resolve, rejected) => {
setTimeout(rejected("111失败"), 1000)
})
const p2 = 222
const p3 = Promise.resolve(333)
const p4 = Promise.reject("444失败")
const Pall = Promise.any([p1,p2, p3, p4]).then(val => {
console.log(val)
})
返回值
javascript
> 222
传入的promise全为reject时
javascript
const p1 = new Promise((resolve, rejected) =>{
setTimeout(rejected("111失败"), 1000)
})
const p2 = 222
const p3 = Promise.resolve(333)
const p4 = Promise.reject("444失败")
const Pall = Promise.any([p1, p4]).catch(val => {
console.log(val)
})
返回值
javascript
> AggregateError: All promises were rejected
Promise.race()
:
race()
接受一个promise数组作为参数,并返回一个Promise。这个返回的 promise,只会受到第一个完成的promise状态影响,当有一个promise完成时其他promise自动终止。
实例
javascript
const p1 = new Promise((resolve, rejected) =>{
setTimeout(() => {rejected("111失败")}, 1000)
})
const p2 = new Promise((resolve, rejected) =>{
setTimeout(() => {resolve("222成功")}, 100)
})
const Pall = Promise.race([p1,p2]).then(
val => {console.log(val)}
).catch(
val => {console.log(val)}
)
返回值
javascript
> "222成功"