天天看點

優化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);
}
           

繼續閱讀