async/await到底是什么?
从字面上理解,async 是“异步的意思,而 await 我们可以简单的认为是 async wait 的简写。所以, async 用于申明一个 function 是异步的, await 是用于等待一个异步方法执行完成。
语法规定,async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果, await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。
async怎么用?
举个简单栗子
async function fn() {
return 'hello world';
}
console.log(fn());
结果如下:
由此可见,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。(通俗讲,async作为一个关键字放在函数前面,它的调用返回了一个promise 对象。)
到这步就有疑问了,返回的是一个promise 对象,那么如何处理这个promise对象获取其返回值?
当然是用原来的方式:then() 链来处理这个 Promise 对象
async函数内部return语句返回的值,会成为then方法回调函数的参数
fn().then(data=>{
console.log(data) //输出hello world
})
那么问题又来了,如果 fn 函数内部抛出错误呢?
async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态,
抛出的错误对象会被catch方法回调函数接收到
async function fn(){
throw new Error('rejected')
}
fn()
.then(v=>{
console.log(v)
})
.catch(e=>{
console.log(e) // Error:rejected
})
如图:
会调用Promise.reject() 返回一个promise 对象
await怎么用?
await 关键字只能放到async 函数里面,await是等待的意思,那么它等待什么呢?它后面跟着什么呢?
其实它后面可以放任何表达式,不过我们更多的是放一个返回promise 对象的表达式,它等待的是promise 对象的执行完毕,并返回结果
举个栗子:
async function func(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
var a= "lxy";
resolve(a)
},1000)
})
}
async function test(){
var b = await func();
console.log(b);
};
test(); // 输出结果 :lxy
分析一下过程:首先调用了test()函数,内部遇到了await,暂停执行代码,直到后面的promise对象也就是func()执行完毕,func()返回的promise开始执行,拿到promise resolve 的值并返回,这时,await拿到返回值并赋值给b,暂停结束,代码接着执行,输出console.log语句。
注意:当js引擎在等待promise resolve 的时候,await并没有真正的暂停工作,它可以处理其它的一些事情,如果我们在test函数的调用后面,console.log 一下,你会发现先执行了后面的console.log代码。
async function test(){
var b = await func();
console.log(b);
};
test();
console.log('先执行')
先执行了console.log语句,隔一秒后再执行了test()方法
为什么要用async/await?
处理由多个 Promise 组成的 then 链的时候,用async/await就会比较方便
举个栗子:
setTimeout(function callback(){
console.log( 'First' )
},1000)
当我们异步函数需要嵌套的时候,如下
setTimeout(function(){
console.log("First")
setTimeout(function(){
console.log("Second")
setTimeout(function(){
console.log("Third")
setTimeout(function(){
console.log("Four")
setTimeout(function(){
console.log("Five")
},1000);
},1000);
},1000);
},1000);
},1000);
看到这,简直要炸了,那我们用async/await来处理一下
function fn(ms){
return New Promise((resolve,reject)=>{
setTimeout( resolve, ms, 'finish')
})
}
async function asyncFn(){
await asyncFn(1000)
console.log('First finish')
await asyncFn(1000)
console.log('Second finish')
await asyncFn(1000)
console.log('Third finish')
await asyncFn(1000)
console.log('Four finish')
await asyncFn(1000)
console.log('Five finish')
return 'all finish'
}
asyncFn().then(v=>{
console.log(v)
})
其实这里的异步函数操作与同步函数操作没什么区别
这样是不是一目了然,结构清晰明了
注:只要有一个await语句后面的 Promise 变为reject,那么整个async函数都会中断执行
那么,万一出现这种情况,如何不影响后续的执行?
这时,我们可以将第一个await放在try…catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行
async function fn() {
try {
await Promise.reject('出错了');
} catch(e) {
}
return await Promise.resolve( 'hi' );
}
f().then(v =>
console.log(v) // 输出结果:hi
)
说明:本文参考了阮老师的ES6教程案例以及各大文章自己理解整理出来的,望有不对地方请指正!