async/await 应用技巧

580 阅读2分钟

关于async/await

  1. 声明一个 async 方法
// 普通的函数声明
async function foo(){}

//声明一个函数表达式
const foo = async function(){}

// async 形式的箭头函数
const foo = async ()=>{}
  1. async 的返回值 async 函数总是会返回一个 Promise 对象

如果 return 关键字后面不是一个 Promise,那么默认调用 promise.resolve 方法进行转换

async function asyncFunction (){
 return 'Hello World'
}
asyncFunction.then((data)=>{
  console.log(data) // Hello World
})

上面的asyncFunction虽然返回了字符串,却能用 then 方法来获得最终值,这是内部将字符串转换成了 Promise 的缘故。

  1. async 函数的执行过程
  • 执行开始
    • 自动生成一个Promise
  • 执行中
    • 如果遇到return/throw 执行立刻退出
    • 如果遇到await 会暂停执行,但不会阻塞主线程,直到await后面的异步操作结束后恢复执行
  • 执行完毕
    • 无论是否使用 await,异步函数都会返回 Promise

最佳实践

虽然async可以让代码看起来像同步代码,但是也不要错过了并行的机会,示例如下,wait 为异步代码,实际生产中可以是一个接口请求等操作。

bad : 最少1000毫秒执行完毕

async function series() {
  await wait(500); 
  await wait(500); // 等待上一个异步结束后执行
  return "done!"; // 累计耗时1000毫秒+
}

good : 最少500毫秒执行完毕

async function parallel() {
  const wait1 = wait(500); // 执行异步
  const wait2 = wait(500); // 执行异步
  await wait1; 
  await wait2;
  return "done!"; // 所有异步接受后  累计耗时500毫秒+
}

其他

不要为了await而await ,注意原本的代码业务逻辑,合理利用并行的情况。 比如有如下的异步代码(回调形式)

a(() => {
  b();
});

c(() => {
  d();
});

改用async 的方式, 如果写成


await a();
await b();
await c();
await d();

用回调再翻译回来就是

a(() => {
  b(()=>{
    c(()=>{
    	d()
    })
  });
});

偏离了原来的业务逻辑 ,变成了串行,继续优化async

const asyncA = a()
const asyncC = c()
await asyncA
 b()
await asyncC
 d()

虽然a和c 并行了,但是原本d只要c结束就可以执行,但是如果a的速度晚于c,就变成了

a(()=>{
  d()
})

也就是d需要等待的时间为a和c的最大值,继续优化async,最终可以通过如下形式还原业务

(async () => {
  await a()
  b()
})()

(async () => {
  await c()
  d()
})()

异常捕获 一般情况可能会通过try catch 捕获,但是如下情况的异常是捕获不到的

async function catchDemo() {
    try {
        // 注意这里是return,不是await
        return Promise.reject(new Error("Oops!"));
    } catch (error) {
        // 代码不会执行到这里
    }
}
catchDemo()

由于async运行的结果是返回一个Promise,所以可以通过.catch捕获

catchDemo().catch((error)=>{
  console.log(error)
})

参考资料:

zhuanlan.zhihu.com/p/36521539

www.freecodecamp.org/news/avoidi…