1. 什么是Promise
Promise 是用来管理异步操作的对象,可以获取成功(或失败)的结果。
基本用法:
- 成功 resolve(成功结果) .then执行
- 失败 reject(失败结果) .then第二个回调函数执行 或者 .catch执行
- .finally 无论成功还是失败都会执行
const p = new Promise<string>((resolve, reject)=>{
// 执行异步操作
})
p.then(res => {}, (err: string) => {}).finally(() => {})
// 或者
p.catch(res => {}).catch((err: string) => {})finally(() => {})
2. Promise的状态
Promise必然处于三种状态中的一种,调用 resolve 和 reject 的本质就是改变状态。
三种状态:
- 待定(pending):初始状态。
- 已兑现(fullfilled):意味着操作成功。
- 已拒绝(rejected):意味着操作失败。
注意:状态的改变不可逆。 调用 resolve 之后再调用 reject,状态还是 已兑现,反之亦然。
3. Promise的静态方法
Promise的静态方法主要有:
- Promise.resolve
- Promise.reject
- Promise.race
- Promise.all
- Promise.allSettled
3.1 Promise.resolve
返回一个成功原因的 Promise 对象。
Promise.resolve('成功原因')
.then(res => {
console.log(res) // 成功原因
})
3.2 Promise.reject
返回一个失败原因的 Promise 对象。
Promise.reject('失败原因')
.catch((err: string) => {
console.log(err) // 失败原因
})
3.3 Promise.race
是什么:race 方法用于处理一组Promise实例,并返回第一个完成异步操作的结果。
应用场景:多个服务器提供相同的数据,但响应时间不同,你想要最快的那个服务器提供的响应数据。
const p1 = new Promise<string>((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 2000)
})
const p2 = new Promise<string>((resolve, reject) => {
setTimeout(() => {
// resolve('p2')
reject('p2')
}, 1000)
})
Promise.race([p1, p2])
.then(res => {
console.log('race成功结果', res) // p2
})
.catch((err:string)=>{
console.log('race失败结果', err) // p2
})
3.4 Promise.all
是什么:all 方法用于处理一组Promise实例,如果所有Promise实例都成功完成,将所有成功的结果作为一个数组返回;如果有任何一个Promise实例失败,返回第一个失败的Promise实例的原因。
缺点:只要有一个失败,则其他所有数据都拿不到。
应用场景:多个请求要么同时拿到成功的数据,要么一个都不要。
const p1 = new Promise<string>((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 2000)
})
const p2 = new Promise<string>((resolve, reject) => {
setTimeout(() => {
// resolve('p2')
reject('p2')
}, 1000)
})
const p3 = new Promise<string>((resolve, reject) => {
setTimeout(() => {
resolve('p3')
}, 1000)
})
Promise.all([p1, p2, p3])
.then(res => {
console.log('all成功结果', res) // p1,p2,p3
})
.catch((err:string)=>{
console.log('all失败结果', err) // p2
})
3.5 Promise.allSettled
相对于 all 方法,allSettled 方法可以获取所有的结果,无论成功还是失败。
获取的结果是对象数组:其中
成功 返回的对象:{ status: ‘fulfilled’, value: ‘成功结果’ }
失败 返回的对象:{ status: ‘rejected’, reason: ‘失败原因’ }
const p1 = new Promise<string>((resolve, reject) => {
setTimeout(() => {
resolve('成功p1')
}, 2000)
})
const p2 = new Promise<string>((resolve, reject) => {
setTimeout(() => {
reject('失败p2')
}, 1000)
})
const p3 = new Promise<string>((resolve, reject) => {
setTimeout(() => {
resolve('成功p3')
}, 1000)
})
Promise.allSettled([p1, p2, p3])
.then(res => {
res.forEach(item=>{
if(item.status == 'fulfilled'){
console.log(item.value)
}else {
console.log(item.reason)
}
// 成功p1 失败p2 成功p3
})
})
4. Promise 的链式编程
Promise的链式编程是用来解决【回调函数地狱】的一种写法,让多层嵌套代码可读性变强。
4.1 什么是回调地狱
回调地狱:多层回调函数嵌套。
产生原因:多个接口请求之间有依赖关系,下一个接口需要上一个接口的数据。
缺点:代码不好维护。
const req = http.createHttp()
req.request('接口1')
.then(res1=>{
req.request('接口2?p=接口1的结果res1')
.then(res2=>{
req.request('接口3?p=接口2的结果res2')
.then(res3=>{
req.request('接口4?p=接口3的结果res3')
.then(res4=>{
req.request('接口5?p=接口4的结果res4')
.then(res5=>{
req.request('接口6?p=接口5的结果res5')
.then(res6=>{
})
})
})
})
})
})
4.2 什么是链式编程
链式编程允许多个操作(如方法调用)链接在一起。
链式编程通常是通过返回同一个类型的对象的方式来实现。
Promise的链式编程写法
const req = http.createHttp()
req.request('接口1')
.then(res1 => {
return req.request('接口2?p=接口1的结果res1')
})
.then(res2 => {
return req.request('接口3?p=接口2的结果res2')
})
.then(res3 => {
return req.request('接口4?p=接口3的结果res3')
})
.then(res4 => {
return req.request('接口5?p=接口4的结果res4')
})
.then(res5 => {
})
.catch((err: string) => {
})
Promise的链式编程特点:
- 后面的.then可以接收到前面.then返回成功状态下的值。
- 后面的.catch可以接收到前面.then返回失败状态下的值。
- 一旦在某个.then里面返回的是一个失败状态的Promise对象,则直接跳过其他的.then进入到.catch执行。
注意点:如果后一个.then需要用到前一个.then的结果,需要在前一个.then中显式指定return
5. async 和 await
5.1 async/await是什么
async/await是一种用于处理异步操作的Promise语法糖。
基本语法:
async 修饰函数 -> 异步函数
await 等待成功结果(Promise对象)
使用async关键字声明一个函数为异步函数(返回值类型是Promise对象)。
使用await关键字等待Promise对象的解析(完成或拒绝),以同步的方式编写异步操作的代码。
5.2 async 函数和 await 的特点
async函数的特点:
- async修饰的函数默认返回的是Promise对象,所以可以放到await关键字后面来调用
- async修饰的函数内部return的数据需要使用 await 或者 .then() 或者 .catch() 来接收
await的特点
- await关键字必须放在async修饰的函数中才能使用
- await关键字后面是一个Promise对象,如果是一个普通值会自动转为Promise对象来执行
- await会等待其后面的Promise对象的成功执行状态,将结果值赋值给 = 号前面的变量
如果Promise是失败状态,则不会再往下继续执行
如果想要执行,需要使用try/catch来捕获错误
使用场景:不能使用在需要花费很长时间的异步处理上。
原因:await后面的Promise对象异步函数如果执行时间很长,会卡住调用方的执行。此时请用回.then()的回调函数