写在前面
之前我写过一篇文章关于JS
中如何解决异步代码挂起的问题Js中异步代码挂起怎么解决? - 掘金 (juejin.cn),文中我主要讲了用Promise
来解决异步问题,我们知道了可以用then
链来解决多层回调问题,但是用then
链的话写起来不够优雅,有点不符合原生JS
写法的意思,async
和await
就很好地解决了这个问题,首先用async
声明一个异步函数,然后再用await
等待异步结果,把以前then
链的结果放到直接放在await
,非常方便。
async/await是什么?
async/await
语法是在2016年时提出的,简单来说async/await
是Promise
的语法糖,async
是异步的意思,await
是等待的意思。async function
申明一个函数里面可能有异步代码需要执行,await
则可以认为是等待一个异步方法执行完成。
async/await的用法
我们直接来看下面的例子:
let data = {}
function getData1() {
return new Promise((resolve, reject) => {
//异步代码
setTimeout(() => {
data = { name: 'song', age: 20 }
resolve()
}, 1000)
})
}
function getData2() {
return new Promise((resolve, reject) => {
//异步代码
setTimeout(() => {
data = { name: 'uiiy', age: 20 }
resolve()
}, 2000)
})
}
function showData() {
console.log(`我正在展示获取到的数据:${JSON.stringify(data)}`);
}
async function handle() {
await getData1()
await getData2()
showData()
}
handle()
在上面的代码中我们可以看到getData1
和getData2
两个函数中都有异步代码,我们用async/await
来解决的话在函数体内和使用then
链解决一样,都需要return
出一个Promise
。不同的点就在于async
新定义了一个异步函数,getData1
和getData2
两个函数在异步函数里面调用,然后在两个函数前面都加上await
。
async/await的特点
async
函数调用会返回一个Promise
对象。
sync function handle() {
//return new Promise(()=>{})
return 'hello'
}
const res = handle()
console.log(res);
上面代码执行结果为:
await
必须写在async
函数里面。
这个特点很好理解,async
和await
是配套使用的,await
规定了要写在 async
里面。
await
会阻塞下一行代码的执行,封装了Promise.then()
。
这也很好理解,我们知道需要耗时的代码都是异步代码,await
加在了有异步代码的函数前面,一定要等这个函数执行完毕了才会执行下面的代码,要不然就解决不了异步代码挂起的问题了。
await
也会返回出一个Promise
对象。
//await
function await() {
return Promise.resolve().then(() => {
})
}
一道面试题
将下面代码async/await
翻译成Promise
function getJson() {
return new Promise((resolve, reject) => {
setTimeout(function () {
console.log(2);
resolve(2)
}, 2000)
})
}
async function testAsync() {
await getJson()
console.log(3);
}
testAsync()
我们可以根据async/await
的特点翻译成下面的代码:
//翻译成Promise.then执行
function testAsync() {
return Promise.resolve().then(() => {
return getJson()
}).then(() => {
console.log(3);
})
}
变化
如果题目中getJson
函数里面没有返回一个Promise
对象上面代码的执行结果会改变吗?
function getJson() {
setTimeout(function () {
console.log(2);
resolve(2)
}, 2000)
}
这里显然是会的,这样这个函数里面的异步代码将会挂起,先是输出3,再输出2
。
注意:
then
也会返回一个Promise
对象
async/await的优点——和Promise比较
- 同步代码编写方式,能处理由多个
Promise
组成的then
链,async/await
从上到下,顺序执行,更符合我们的编写习惯。 - 同步代码和异步代码可以一起编写,用
Promise
最好将同步代码和异步代码放在不同的then节点中,这样结构更加清晰,而用async/await
整个书写习惯都是同步的,不需要纠结同步和异步的区别。 - 语法简洁清晰,节省了很多不必要的匿名函数。
- 减少不必要的中间变量,更清晰明确的错误堆栈。
async/await的局限
- 降低了我们阅读理解代码的速度,此前看到
.then()
就知道是异步,现在需要识别async
和await
关键字。
可以看出,
async/await
的优势大部分都是从开发调试效率提升层面来讲的,提到的局限也只有不痛不痒的,所以说async/await
整体还是优雅的。
最后
async/await
相比于Promise
是更优越的异步处理方案,但我们相信这一定不是终极处理方案。随着前端工程化的深入,一定有更多、更复杂、更精细的异步问题出现,同时也会有迎合这些问题的解决方案出现。最后感谢各位的观看,我们下篇文章见~