promise与async/await解析
问题引入
什么是回调地狱
回调函数中嵌套回调函数的情况就叫做回调地狱。回调地狱就是为是实现代码顺序执行而出现的一种操作。
实例
setTimeout(()=>{
console.log('这是第一步')
setTimeout(()=>{
console.log('这是第二步');
setTimeout(()=>{
console.log('这是第三步');
},1000)
},2000)
},3000)
上面代码看起来没有什么问题,但是如果回调函数的结构十分复杂,那么层层嵌套就会让代码的结构不清晰。
回调地狱产生的问题
嵌套层次很深,可读性差,难以维护
无法正常使用return 和throw
无法正常检索堆栈信息
多个回调之间难以建立联系
解决回调地狱的方法
1、promise
2、async/await
Promise
什么是promise
1、Promise是js中的一个原生对象,是一种异步编程的解决方案,可以替换掉传统的回调函数解决方案。
2、它通过引入一个回调,避免更多的回调.
简单说Promise就是一个容器,里面保存着某个未来才会结束的事件 (通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。
promise实现
Promise有3个状态:
pending(初始)
,resloved(成功)
,rejected(失败)
。
通过new 可以创建一个Promise实例对象。
用法:
A、构造函数有两个参数:resloved和rejected,都是回调函数
B、resloved函数:将Promise对象的状态从“未完成”变成“成功”(即从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去
C、rejected函数:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
E、.then():接收resloved函数传递过来的信息
F、.catch():接收rejected函数传递过来的信息
Promise的链式编程可以保证代码的执行顺序,前提是每一次在then做完处理后,一定要return一个Promise对象,这样才能在下一次then时接收到数据。
function fun(str){
//创建promise对象
let promise = new Promise((resolve,reject)=>{
var flag = true;
setTimeout(()=>{
if(flag){//模拟异步调用成功
resolve(str);//将成功的信息传递出去
}else{//模拟异步调用失败
reject('error')//将失败的信息传递出去
}
})
})
return promise;
}
fun('这是第一步').then((data)=>{
console.log(data);
return fun('这是第二步')
}).then((data)=>{
console.log(data);
return fun('这是第三步')
}).then((data)=>{
console.log(data)
}).catch((data)=>{
console.log(data)
})
Promise–all的用法
Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。用Promise.all来执行,all接收一个数组参数,里面的值最终都返回Promise对象。
function getWidth() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(10)
},1000)
})
}
function getHeight() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(20)
},1000)
})
}
Promise.all([getWidth(),getHeight()]).then((data)=>{
console.log(data);
})
Promise–race的用法
顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([f1,f2,f3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
function getWidth() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(10)
},2000)
})
}
function getHeight() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(20)
},1000)
})
}
function getLength() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(30)
},3000)
})
}
Promise.race([getWidth(),getHeight(),getLength()]).then((data)=>{
console.log(data);
})
async/await
Promise虽然跳出了异步嵌套的怪圈,用链式表达更加清晰,但是我们也发现如果有大量的异步请求的时候,流程复杂的情况下,会发现充满了屏幕的then,看起来非常吃力。
使用async/await基本规则
await关键字只能在使用async定义的函数中使用
await后面可以直接跟一个 Promise实例对象(可以跟任何表达式,更多的是跟一个返回Promise对象的表达式)
await函数不能单独使用
await可以直接拿到Promise中resolve中的数据。
function fun(str){
//创建promise对象
let promise = new Promise((resolve,reject)=>{
var flag = true;
setTimeout(()=>{
if(flag){//模拟异步调用成功
resolve(str);//将成功的信息传递出去
}else{//模拟异步调用失败
reject('error')//将失败的信息传递出去
}
})
})
return promise;
}
//封装一个执行上述任务的async函数
async function test(){
let res1 = await fun('这是第一步')//await直接拿到fun函数返回的promise数据
let res2 = await fun('这是第二步')
let res3 = await fun('这是第三步')
console.log(res1,res2,res3);
}
test();
捕捉错误
await等待的虽然是promise对象,但
不必写.then(..)
,直接可以得到返回值。
既然.then(…)不用写了,那么.catch(..)也不用写
,可以直接用标准的try…catch语法捕捉错误。
function fun(str){
//创建promise对象
let promise = new Promise((resolve,reject)=>{
var flag = false;
setTimeout(()=>{
if(flag){//模拟异步调用成功
resolve(str);//将成功的信息传递出去
}else{//模拟异步调用失败
reject('error')//将失败的信息传递出去
}
})
})
return promise;
}
async function test(){
try{
let tes = await fun('err')
console.log(tes);
}catch(err){
console.log(err);
}
}
test();