【譯】JavaScript中的async/await

call_me_R發表於2019-05-03

非同步的JavaScript從未如何簡單!過去段時間,我們使用回撥。然後,我們使用promises。現在,我們有了非同步功能函式。

非同步函式能夠使得(我們)編寫非同步JavaScript更加容易,但是,它自帶一套陷阱,對初學者很不友好。

在這個由兩部分組成的文章中,我想分享下你需要了解的有關非同步函式的內容。【PS:另一部分暫不打算翻譯】

非同步功能

非同步功能函式包含async關鍵詞。你可以在正常的函式宣告中使用它:

async function functionName (arguments) {
  // Do something asynchronous
}
複製程式碼

你也可以使用箭頭函式。

const functionName = async (arguments) => {
  // Do something asynchronous
}
複製程式碼

非同步函式總是返回promises

(非同步函式)它不管你返回什麼。其返回值都是promise

const getOne = async _ => { 
  return 1 
} 

const promise = getOne()
console.log(promise) // Promise 
複製程式碼

筆記:在接著往前讀之前,你應該知道什麼是JavaScript Promises知識點,以及如何使用它們。否則,它會開始變得混亂。這篇文章會幫助你熟悉JavaScript Promise。

await關鍵字

當你呼叫promise時,你會在then中處理下一步,如下:

const getOne = async _ => { 
  return 1 
} 

getOne()
  .then(value => {
    console.log(value) // 1
  })
複製程式碼

await關鍵字允許你等待promise去解析。一旦解析完promise,它就會返回引數傳遞給then呼叫。

const test = async _ => {
  const one = await getOne()
  console.log(one) // 1
}

test()
複製程式碼

返回await

在返回承諾(promise)之前沒有必要等待(await)。你可以直接退回承諾。

如果你return await些內容,則你首先是解決了原先promise。然後,你從已經解析的內容(resolved value)建立新的promise。return await真的沒做什麼有效的東西。無需額外的步驟。

// Don't need to do this 
const test = async _ => {
  return await getOne()
}

test()
  .then(value => {
    console.log(value) // 1
  })
複製程式碼
// Do this instead
const test = async _ => {
  return getOne()
}

test()
  .then(value => {
    console.log(value) // 1
  })
複製程式碼

注意:如果你不需要await,則不需要使用非同步功能(async function)。上面的例子可以改寫如下:

// Do this instead
const test = _ => {
  return getOne()
}

test()
  .then(value => {
    console.log(value) // 1
  })
複製程式碼

處理錯誤

如果一個promise出錯了,你可以使用catch呼叫來處理它,如下所示:

const getOne = async (success = true) => { 
  if (success) return 1
  throw new Error('Failure!')
} 

getOne(false)
  .catch(error => console.log(error)) // Failure!
複製程式碼

如果你想在一個非同步函式中處理錯誤,你需要呼叫try/catch

const test = async _ => {
  try {
    const one = await getOne(false)
  } catch (error) {
    console.log(error) // Failure!
  }
}

test()
複製程式碼

如果你有多個await關鍵字,錯誤處理可能變得很難看...

const test = async _ => {
  try {
    const one = await getOne(false)
  } catch (error) {
    console.log(error) // Failure!
  }

  try {
    const two = await getTwo(false)
  } catch (error) {
    console.log(error) // Failure!
  }

  try {
    const three = await getThree(false)
  } catch (error) {
    console.log(error) // Failure!
  }
}

test()
複製程式碼

還有更好的方法。

我們知道非同步函式總是返回一個promise。當我們呼叫promise時,我們可以在catch呼叫中處理錯誤。這意味著我們可以通過新增.catch來處理非同步函式中的任何錯誤。

const test = async _ => {
  const one = await getOne(false)
  const two = await getTwo(false)
  const three = await getThree(false)
}

test()
  .catch(error => console.log(error)))
複製程式碼

注意:Promise的catch方法只允許你捕獲一個錯誤。

多個awaits

await阻止JavaScript執行下一行程式碼,直到promise解析為止。這可能會導致程式碼執行速度減慢的意外效果。

為了實際演示這點,我們需要在解析promise之前建立一個延遲。我們可以使用sleep功能來建立延遲。

const sleep = ms => {
  return new Promise(resolve => setTimeout(resolve, ms))
}
複製程式碼

ms是解析前等待的毫秒數。如果你傳入1000sleep函式,JavaScript將等待一秒才能解析promise。

// Using Sleep
console.log('Now')
sleep(1000)
  .then(v => { 
    console.log('After one second') 
  })
複製程式碼

sleep

假設getOne需要一秒來解析。為了建立這個延遲,我們將1000(一秒)傳入到sleep。一秒過後,sleeppromise解析後,我們返回值1。

const getOne = _ => {
  return sleep(1000).then(v => 1)
}
複製程式碼

如果你使用await getOne(),你會發現在getOne解析之前需要一秒鐘。

const test = async _ => {
  console.log('Now')

  const one = await getOne()
  console.log(one)
}

test()
複製程式碼

block-1

現在,假設你需要處理三個promises。每個promise都有一秒鐘的延遲。

const getOne = _ => {
  return sleep(1000).then(v => 1)
}

const getTwo = _ => {
  return sleep(1000).then(v => 2)
}

const getThree = _ => {
  return sleep(1000).then(v => 3)
}
複製程式碼

如果你連續await這三個promises,你將要等待三秒才能解析完所有promises。這並不好,因為我們強迫JavaScript在做我們需要做的事情之前等待了兩秒鐘。

const test = async _ => {
  const one = await getOne()
  console.log(one)

  const two = await getTwo()
  console.log(two)

  const three = await getThree()
  console.log(three)

  console.log('Done')
}

test()
複製程式碼

block-2

如果getOnegetTwogetThree可以同時獲取,你將節省兩秒鐘。你可以使用Promise.all同時獲取這三個promises。

有三個步驟:

  1. 建立三個promises
  2. 將三個promises新增到一個陣列中
  3. 使用Promise.allawaitpromises陣列

如下所示:

const test = async _ => {
  const promises = [getOne(), getTwo(), getThree()]
  console.log('Now')

  const [one, two, three] = await Promise.all(promises)
  console.log(one)
  console.log(two)
  console.log(three)

  console.log('Done')
}

test()
複製程式碼

block-3

這就是你需要了解的基本非同步功能函式!我希望這篇文章為你掃除了些障礙。

筆記:這篇文章是Learn JavaScript的修改摘錄。如果你發現本文有用,你可能需要去檢視它。

後話

原文:zellwk.com/blog/async-…

文章首發:github.com/reng99/blog…

至此,系列文callbacks,promisesasync/await共三篇文章已經完成~

更多內容:github.com/reng99/blog…

相關文章