天天看点

优化JS中的Async/Await 使用

JS中调用 async 函数时会返回一个 Promise 对象(隐式转换)。当async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值,当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。

在async 函数中如果遇见 await 表达式,则 async 函数会暂停执行,等待表达式中的 Promise 解析完成后继续执行 async 函数并返回结果。

基于上面的定义,我们来对比一下如下的代码,我们就知道优化点如何排查了。

function resolveAfter2Seconds(x) {
  return new Promise(resolve =>setTimeout(() =>  resolve(x), ))
}

async function fn1(x) {
  var a = resolveAfter2Seconds()
  var b = resolveAfter2Seconds()
  return x + await a + await b
}

// prints 60 after 2 seconds
fn1().then(v => console.log(v))

async function fn2(x) {
  var a = await resolveAfter2Seconds()
  var b = await resolveAfter2Seconds()
  return x + a + b
}

// prints 60 after 4 seconds
fn2().then(v => console.log(v))
           

上面的代码演示代码中,我们可以发现,不同的 await 位置声明,会直接影响到函数执行的时间。

同时,我们在处理 async 函数的返回时,针对其 reject 的场景时,try-catch 模块来进行捕获,但由于try-catch会创建独立的作用域(这算是很老的一个点了,不知新版的V8有没有进行过优化),所以会在性能上有一些损失,但是相对于代码的可读性,这一点损失也无所谓啦。

async function fn(url) {
  let v
  try {
    v = await doSomething(url)
  } catch (e) {
    v = await handlerError(url)
  }
  return success(v)
}

// 比价丑陋的写法,通过牺牲代码的可读性来避免作用域的开辟

async function fn(url) {
  let v
  v = await doSomething(url).catch(err => {
      v = await handlerError(url)
  })
  return success(v);
}
           

继续阅读