1.async和await在干什么
任意一个名称都是有意义的,先从字面意思来理解,async是“异步”的简写,而await可以认为是async wait的简写。所以应该就很好理解async用于声明一个function是异步的,而await用于等待一个异步方法执行完成。
2.async
带有async
关键字的函数,是声明异步函数的,返回值是Promise
对象,如果async
关键字函数返回的不是promise
,会自动用Promise.resolve()
包装
async function test() {
return 'test'
}
test()
//返回的是一个promise对象
3.await
await
等待右侧表达式的结果,这个结果是promise对象或者其他值。
- 如果等到的不是一个
promise
对象,那await
表达式的运算结果就是它等到的东西 - 如果等到的是一个
promise
对象,await
就忙起来了,它会阻塞后面的代码,等着promise
对象resolve
,然后得到resolve
的值,作为await
表达式的运算结果
function test(){
return new Promise(resolve=>{
setTimeout(() => resolve("test"), 2000);
})
}
const result = await test();
console.log(result)
console.log('end');
输入以上的代码,其实不会输出结果,会报错
原因:js要使用async和await请在模块中使用,就是说你应该把代码放到模块中
解决方法:需要在script标签中的type改为module,这样就可以运行异步代码了
所以为了避免造成阻塞,await必须用在async函数中,async函数调用不会造成阻塞
function test() {
return new Promise(resolve => {
setTimeout(() => resolve("test"), 2000);
});
}
async function test2() {
const result = await test();
console.log(result);
}
test2();
console.log('end')
//结果,先执行'end',两秒后执行'test'
//如果await用在普通函数中,会报错,如下:
4.async/await的执行顺序
遇到await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,继续执行await后面的代码,以下的代码分析:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script type="module">
async function test1(){
console.log('start test1');
console.log(await test2());
console.log('end test1');
}
async function test2(){
console.log('test2');
return await 'return test2 value'
}
test1()
console.log('start async');
setTimeout(()=>{
console.log('setTimeout');
},0)
new Promise ((resolve,reject)=>{
console.log('promise1');
resolve();
}).then(()=>{
console.log('promise2');
})
console.log('end async');
</script>
</html>
//执行结果
1.首先执行宏任务,执行test1函数,执行'start test1'
2.遇到await,先执行右边test2中的'‘test2',中断了后面的代码,执行test1外面的同步代码,
3.执行'start async'
4.遇到setTimeout,推到下一个宏任务队列中
5.执行promise里面的同步代码'promise1'
6.运行到promise().then,发现是promise对象,推到微任务队列中
7.执行'end async'
8.test1外面的同步代码执行结束后,回到test1中,'await test2()'执行完成后返回promise{<resolve>:'return test2 value'},是promise对象,推到微任务队列中
9.此时第一个宏任务结束,执行所有的微任务,因为微任务队列中是先进先出,所以先执行'promise2',后执行'return test2 value'
10.执行test2完成后,后面的代码不再阻塞,执行'end test1'
执行下个宏任务,既执行'setTimeout'
5.async/await的优缺点
优点:
相对于promise,async/await处理then的调用链,代码要清晰很多,几乎和同步代码一样
缺点:
滥用await可能会导致性能问题,因为await会阻塞代码