Promise和aysnc/await总结
引言
为什么要了解Promise?
Promise正如其名【承诺】就是一个异步任务 它的核心是进行链式调用,通过【链式调用】可以避免回调地狱【回调嵌套回调无穷尽也】的问题
同时,配合官方加成的语法async和await,就可以实现回调的避免,从而让代码更加优雅而好理解,让我们在实际开发中能够写好异步函数。
首先 认识Promise
Promise有两个阶段、三个状态
两个阶段:未决阶段和已决阶段
三个状态:
- 未决阶段:挂起状态
- 已决阶段:完成状态、失败状态
Promise最开始为未决阶段unsettled,状态为pending(挂起状态),我们需要将Promise从未决阶段转换成已决阶段。
Promise(callback)
new Promise((resolve,reject)=>{ });
这里需要讲到Promise的参数了
Promise(callback)
对,Promise的参数为一个回调函数,其中按照先后来看,有按两个参数
resolve和reject
分别能够将Promise从挂起状态pending转换成 完成fulfilled/失败rejected状态
在一个Promise中
如果运行resolve()则转换成完成状态
如果运行reject()则转换成失败状态
我们需要根据实际逻辑决定是调用resolve()还是reject()
在转为已决阶段之后,Promise就会返回一个值,这个值是传在resolve和reject中的数据。
接下来需要进行后续处理
Promise的后续处理
Promise的后续处理对应着一个函数.then()
其实不是.then()方法,应该说:Promise对象可以通过
.访问符来调用then()方法。
.then()方法中可以按顺序放入两个回调函数,
- 第一个回调函数是对成功的后续处理
- 第二个回调函数是对失败的后续处理
这两个回调函数都可以写上,实际调用哪个要看Promise对象已决阶段是成功还是失败。
而现在,一般使用.then()中放入一个回调函数,具体规范为:
- 用
.then专门进行成功的后续处理- 用
.catch专门进行失败的后续处理
Promise的链式调用
像这样
Promise((resolve,reject)=>{
// ...
}).then((data)=>{
// 成功后续处理逻辑
}).catch((reason)=>{
// 失败后续处理逻辑
});
这上面就用到了Promise的核心:【链式调用】
链式调用避免了回调地狱,也就是说不需要【回调函数嵌套回调函数无穷尽】了
【Promise后续处理】概念纠正:
要知道:后续处理是一个Promise,后续处理只是后续处理 而.then()中回调函数进行后续处理完毕后返回的是一个Promise
这个Promise的状态仅被处理逻辑中 return 决定
- 如果处理逻辑报错或者手动报错,则状态为Rejected,携带值为错误信息,用于之后的catch的回调函数中使用
- 只要不出错,状态就是Fulfilled,携带值为【return中的值】,用于之后的then中的回调函数中使用。
如果说then中的回调函数尚未执行,而把其赋值给一个变量,可以发现这个变量的Promise对象对应的状态为pending。 【then()中的回调函数尚未执行并不妨碍then()返回一个Promise】。只是这个Promise的状态和值在then()中的回调函数执行完毕后再被确定。
如果.then()/.catch()链接的Promise对象的状态为相反,则只作为传递者,或说会被跳过,直到有处理相应状态的函数为止。
由于Promise是异步任务,所以同步代码不会等待Promise执行,以下为一个典型示例:
// 下面代码的输出结果是什么
const pro1 = new Promise((resolve,reject)=>{
let data = 1;
console.log(data);
setTimeout(()=>{
resolve(data);
},1000); })
const pro2 = pro1.then((data)=>{
console.log(++data);
return data;
})
const pro3 = pro2.then((data)=>{
console.log(++data);
return data;
})
console.log(pro1,pro2,pro3);
//
setTimeout(()=>{
console.log(pro1,pro2,pro3);
},2000);
/**
* 完整执行顺序总结
同步代码:
定义 pro1,输出 1。
定义 pro2 和 pro3,输出 pro1, pro2, pro3 的状态(Pending)。
异步代码:
1秒后 pro1 完成,输出 2。
pro2 完成,输出 3。
pro3 完成。
2秒后,输出 pro1, pro2, pro3 的最终状态和值。
1 Promise { <pending> } Promise { <pending> } Promise { <pending> }
2
3
Promise { 1 } Promise { 2 } Promise { 3 }
*/
Promise的静态方法
工具方法有
Promise.resolve()
Promise.reject()
分别直接返回一个成功状态/失败状态的Promise对象
说明:
Promise.resolve(1);
// 等价于
new Promise((resolve)=>{
resolve(1);
})
而其他静态方法
Promise.all([Promise对象数组])
有三种情况
- Promise对象运行结果都为完成状态,则返回一个
成功状态的Promise对象,数据为装有所有Promise运行resolve(data)中data的数组. - 存在Promise的运行结果为失败状态,则返回一个
失败状态的Promise对象,数据为首个失败的Promise对象的失败原因。 - 存在Promise的运行状态仍为挂起状态(Pending),则返回一个
Pending状态的Promise对象
Promise.any([Promise对象数组])
有三种情况
- 存在Promise对象的运行结果为完成状态,则返回一个
完成状态的Promise对象,数据为首个完成的Promise对象的数据 - Promise对象的运行结果都为失败状态,则返回一个
失败状态的Promise对象,数据为装有所有Promise的失败原因的数组 - 存在Promise的运行状态仍为挂起状态(pending),则返回一个
Pending状态的Promise对象
Promise.allSettled([Promise对象数组])
有两种情况
- 全部Promise对象运行结果为已决阶段,则返回一个
成功状态的Promise对象,数据为装有所有Promise对象运行结果的状态和数据的数组,单个数据格式为{ status:'xxx',value:... } - 存在Promise对象仍为Pending状态,则返回一个Pending状态的Promise对象
Promise.race([Promise对象数组])
返回一个Promise对象,状态和值由最先转变为已决状态的Promise对象确定。
async/await
官方规定的async/await语法
作用:避免了回调函数的使用
async
- async修饰的函数为一个异步函数,返回一个Promise
- 标记了async的函数就可以像Promise一样使用
- 函数return 的值相当于Promise中resolve(data)中的data
await
- await 表示等待一个异步任务完成,也就是等待一个Promise执行完毕
- 如果await修饰的不是异步任务,则会把它变成一个异步任务
- 由于await修饰的是一个异步函数,则await必须用在async修饰的函数中
- await避免了回调函数
async function m(){
return 123; // 相当于返回一个完成状态的Promise,resolve(data)中的data为123
}
// 使用await搭配
async functoin test(){
const res = await m();
console.log(res);
}
//等价于
asycn function test_ (){
m().then((data)=>{
console.log(data);
})
}
经过我的分析:
await避免回调的原理就是,await会等待其修饰的Promise对象,其修饰的Promise会返回一个值,值为resolve(data)中的data,理论上来讲如果失败则值为reject(reason)中的reason,但是await只是等待Promise对象的完成,如果失败即reject(reason)/抛错 则需要做失败相应处理catch 可以使用try-catch语句 以避免回调,并且使得异步任务的处理变得优雅直观
try{
const reason = '不告诉你为什么'
const res = await Promise.reject(reason);
}catch(err){
console.log(err)
}
// >> 不告诉你为什么
OK,到此呢,Promise、async/await就告一段落了
Promise 两个阶段,三个状态,resolve/reject将Promise对象从未决阶段转为已决阶段的相应状态。
Promise 链式调用,
.then(callback)进行完成状态的后续处理,.catch(callback)进行失败状态的后续处理,它们都会返回一个Promise,
Promise的状态和值由
return决定,
- 如果return一个
普通值则状态是完成状态,- 如果return一个
Promise则按照这个Promise的状态和值,- 如果
抛出错误比如使用throw,那么状态为失败状态rejected,数据为错误信息。在Promise的链式调用链中,如果后续处理不是相应状态的后续处理,则那部分后续处理会类似于被
跳过,只起到一个传递的作用。Promise的链式调用
避免了回调地狱
async/await
async修饰的函数为一个异步函数,return返回一个Promise,用async修饰的函数可以当成Promise来使用。await修饰一个异步任务,如果不是异步任务则会转换成异步任务,即转换成Promise,它表示等待所修饰的异步任务完成,其避免回调函数的原因在于能够等待Promise完成然后返回resolve(data)中的data然后我们可以用一个变量接住这个data。来进行后续处理。- 如果
await修饰的Promise抛错或失败了,则需要用catch处理 所以一般可以把await放在一个try-catch中,这样就完全避免了使用.then()和.catch()回调。当然并不是必须放try-catch中,因为开发人员可以通过开发者工具看到,而用户不需要看到这个err,他们不是去解决程序问题。 - 同时一个重点是:由于
await修饰的是一个异步任务,所以await一定要放在一个async修饰的函数中。async/await避免了回调函数。
OK,Promise和async/await的总结就到这里了,我是LC_Happy祝好!
这里也感谢渡一的课程了