最近在使用 koa 框架的时候,发现中间件在使用 generator 时,控制台会抛出警告,提示在之后的 koa 版本中,将会移除对 generator 的支持,而改用 async
最然在 koa2 中 generator 依然可用,但是强迫症真的不想在控制台看到这样的警告,于是就大致学习了一下 async 函数(注:async 函数是 ES2017 的标准)
在跟作者一起学习 async 函数之前,小伙伴们可以先行看下下面的这三篇文章:
看这一篇就够了!浅谈ES6的Promise对象
Generator 函数语法
Generator函数的异步用法
什么是 async 函数
async 函数算是一个语法糖,使异步函数、回调函数在语法上看上去更像同步函数
async function asyncLoadData (urlOne, urlTwo) {
let dataOne = await loadData (urlOne)
let dataTwo = await loadData (urlTwo)
}
在上面的代码中,loadData
方法是异步获取数据的方法
可以看到,在 async 函数中,出现了一个陌生的关键字await
——这个关键字只能够在 async 函数中使用,否则将会报错,它的意思是紧跟在其后面的表达式需要被等待执行结果
小伙伴们有没有觉得上面的代码其实和 generator 函数有点类似呢?写成 generator 的话,应该是类似下面的函数:
function * asyncLoadData (urlOne, urlTwo) {
let dataOne = yield loadData (urlOne)
let dataTwo = yield loadData (urlTwo)
}
但是 generator 与 async 的区别并不仅仅是将*
改为async
,将yield
改为await
generator 和 async 的区别
内置执行器
我们知道 generator 函数需要通过调用next()
方法,才能往后执行到下一个yield
,但是 async 函数却不需要,它能够自动向后执行
更易理解
如果你不曾了解过 generator 和 async 函数,那我想你一定无法直观的理解 generator,但是却可以轻易理解 async,这一点仅从字面意思就变现的很清楚了
更适用
yield
命令后面只能跟随Trunk
或Promise
,但是await
后面除了可以是Promise
,也可以是普通类型,但是这样就和同步没有任何区别了
返回值
generator 返回的是一个遍历器对象,而 async 返回的是一个 Promise 对象
async 语法
async 返回一个Promise
,因此这个函数可以通过then
添加回调函数,那么怎么向then
中的回调添加参数呢?async 函数中 return 的结果将作为回调的参数
async function test () {
return 'this is a test async function'
}
test().then(
resolveArg => console.log(resolveArg)
)
// 输出结果
// this is a test async function
同样,当 async 函数内部抛出一个错误时,也会被 catch 到,下面三种 catch 错误的方式都可以:
async function errorTest () {
throw new Error('this is an error');
}
// 在 then 的回调中捕获错误
errorTest().then(
resolve => console.log(resolve),
error => console.log(error)
)
// 在 Promise 的 catch 方法中捕获
errorTest().catch(
error => console.log(error)
)
// 在 try...catch 语句中捕获
try{
errorTest()
} catch (error) {
console.log(error)
}
await 命令
前面说了await
命令后面可以是Promise
也可以是普通数据类型,但如果是普通数据类型的话,会自动转换成状态为resolve
的Promise
如果await
后面的Promise
状态转变成了reject
,那么整个 async 函数都会停止执行,并且抛出相应的错误。即使这里没有return
,也一样可以传入错误回调的参数
所以当一个 async 函数中有多个 await
命令时,如果不想因为一个出错而导致其与的都无法执行,应将await
放在try...catch
语句中执行
async function testAwait () {
try {
await func1()
await func2()
await func3()
} catch (error) {
console.log(error)
}
}
并发执行 await 命令
当一个 async 函数中有多个await
时,这些 await
是继发执行的,只有当前一个await
后面的方法执行完毕后,才会执行下一个
如果我们前后的方法由依赖关系,继发执行是没有问题的,但是如果并没有任何关系的话,这样就会很耗时,所以需要让这些await
命令同时执行,也就是并发执行
// 方法 1
let [res1, res2] = await Promise.all([func1(), func2()])
// 方法 2
let func1Promise = func1()
let func2Promise = func2()
let res1 = await func1Promise
let res2 = await func2Promise
async 函数的学习到这里就结束了,但是这并不意味着 async 的用法只有这些,我们在学习了基础以后,更要把它与其他的知识相结合起来,才能写出更可靠更优质的代码!
如果你发现文中有任何错误的话,都欢迎指正,让我们一起学习进步!
扫码关注前端周记公众号
网友评论