了解
ES7 提出的async 函数,让 JavaScript 对于异步操作有了终极解决方案;async函数实际上是Generator函数的语法糖,使用关键字async来表示,在函数内部使用await来表示异步,相较于Generator,有以下改进:
- 内置执行器。Generator 函数的执行必须依靠执行器,而 Aysnc 函数自带执行器,调用方式跟普通函数的调用一样
- 更好的语义。async 和 await 相较于 * 和 yield 更加语义化
- 更广的适用性。co 模块约定,yield 命令后面只能是 Thunk 函数或 Promise对象。而 async 函数的 await 命令后面则可以是 Promise 或者 原始类型的值(Number,string,boolean,但这时等同于同步操作)
- 返回值是 Promise。async 函数返回值是 Promise 对象,比 Generator 函数返回的 Iterator 对象方便,可以直接使用 then() 方法进行调用
为什么使用
一个函数如下:
function fetchUser() {return new Promise((resolve, reject) => {axios('http://xxx/XXX').then((data) => {resolve(data.json());}, (error) => {reject(error);})});}
使用promise调用如下:需要使用then函数,如果有多重调用,虽然不会出现回调地狱,但是出现多层嵌套的情况,语义化不明显,代码流出也不能很好的表示执行。。
/*** Promise 方式*/function getUserByPromise() {fetchUser().then((data) => {console.log(data);}, (error) => {console.log(error);})}getUserByPromise();
使用async方式,能够完美解决多层嵌套问题,并且语义明显、流程清晰
/*** async 方式*/async function getUserByAsync(){let user = await fetchUser();return user;}getUserByAsync().then(v => console.log(v));
实际使用
初步使用
- 每一个async函数在执行之后,都会自动返回一个Promise对象:
- 如果我们手动在async函数中使用return关键字返回一个直接量,async就会把这个直接量通过Promise.resolve()封装成Promise对象
- 如果async函数没有返回值,则它返回Promise.resolve(undefined)
async test() {// 什么都不写}async test1() {let rel = await Promise.resolve('success')return rel}let result = test()let result1 = test1()console.log(result) // 打印出Promise对象console.log(result1) // 打印出Promise对象
- await必须在async函数里面使用,否则会报错
- await后面需要跟Promise对象,不然就没有意义,而且await后面的Promise对象不必写then,因为await的作用之一就是获取后面Promise对象成功状态传递出来的参数,如下图:

错误处理
await可以直接获取到后面Promise成功状态传递的参数,但是却捕捉不到失败状态;如果第一个await发生错误,后面的await将形成阻塞。所以,我们可以通过两种方式来进行错误捕捉
1、因为async返回的原本就是一个Promise对象,所以我们可以直接在调用的时候跟一个catch回调即可
// 紧跟上面例子test1().then(response => {console.log(response)}).catch(error => {// 捕捉异常console.log(error)})
2、在await外面包裹一层try…catch,进行错误的捕捉
try {let result = await performanceApi.getPerformanceManageList(params)let {data} = result} catch (error) {// 异常捕捉console.log(error)}
3、可能有用,可以了解:使函数同时返回两个值,如下:
async function test () {try {let res = await asyncFun()return [null, res]} catch (e) {return [e, null]}}async function func() {let [err, res] = await errorCaptured(asyncFunc)if (err) {//... 错误捕获}//...}
Async/await的陷阱
虽然await让你的代码看起来想同步的,但是一定要记住,这些方法其实还是在以异步的方式执行,以下代码使没有必要的:
async test(authorId) {// 这样写就意味着:fun1执行完,才会执行fun2,而fun1和fun2是没有依赖关系的,这样执行会花费多余的时间,不合理!const rel1 = await fun1()const rel2 = await fun2()return {rel1,rel2}}
应该修改为,异步执行,没有顺序
async test(authorId) {// 提前执行const relPromise = fun1()const relsPromise = fun2()const rel1 = await relPromiseconst rel2 = await relsPromisereturn {rel1,rel2}}

