什么是 async 函数
async 函数算是一个语法糖,使异步函数、回调函数在语法上看上去更像同步函数
1 2 3 4 5 6 7 8 9 10 11 12
| async function asyncLoadData (urlOne, urlTwo) { let dataOne = await loadData (urlOne) let dataTwo = await loadData (urlTwo) } ```
在上面的代码中,`loadData`方法是异步获取数据的方法 可以看到,在 async 函数中,出现了一个陌生的关键字`await`——这个关键字只能够在 async 函数中使用,否则将会报错,它的意思是紧跟在其后面的表达式需要被等待执行结果 上面的代码其实和 generator 函数有点类似呢?写成 generator 的话,应该是类似下面的函数: ```js 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 的结果将作为回调的参数
1 2 3 4 5 6 7 8 9 10
| async function test () { return 'this is a test async function' }
test().then( resolveArg => console.log(resolveArg) )
|
同样,当 async 函数内部抛出一个错误时,也会被 catch 到,下面三种 catch 错误的方式都可以:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| async function errorTest () { throw new Error('this is an error'); }
errorTest().then( resolve => console.log(resolve), error => console.log(error) )
errorTest().catch( error => console.log(error) )
try{ errorTest() } catch (error) { console.log(error) } ```
### await 命令
前面说了`await`命令后面可以是`Promise`也可以是普通数据类型,但如果是普通数据类型的话,会自动转换成状态为`resolve`的`Promise` 如果`await`后面的`Promise`状态转变成了`reject`,那么整个 async 函数都会停止执行,并且抛出相应的错误。即使这里没有`return`,也一样可以传入错误回调的参数 所以当一个 async 函数中有多个 `await`命令时,如果不想因为一个出错而导致其与的都无法执行,应将`await`放在`try...catch`语句中执行 ```js async function testAwait () { try { await func1() await func2() await func3() } catch (error) { console.log(error) } }
|
并发执行 await 命令
当一个 async 函数中有多个await
时,这些 await
是继发执行的,只有当前一个await
后面的方法执行完毕后,才会执行下一个 如果我们前后的方法由依赖关系,继发执行是没有问题的,但是如果并没有任何关系的话,这样就会很耗时,所以需要让这些await
命令同时执行,也就是并发执行
1 2 3 4 5 6 7 8
| let [res1, res2] = await Promise.all([func1(), func2()])
let func1Promise = func1() let func2Promise = func2() let res1 = await func1Promise let res2 = await func2Promise
|