【譯】JavaScript中的async/await
非同步的 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
是解析前等待的毫秒數。如果你傳入 1000
到 sleep
函式,JavaScript將等待一秒才能解析promise。
// Using Sleep console.log('Now') sleep(1000) .then(v => { console.log('After one second') }) 複製程式碼

假設 getOne
需要一秒來解析。為了建立這個延遲,我們將 1000
(一秒)傳入到 sleep
。一秒過後, sleep
promise解析後,我們返回值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() 複製程式碼

現在,假設你需要處理三個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() 複製程式碼

如果 getOne
, getTwo
和 getThree
可以同時獲取,你將節省兩秒鐘。你可以使用 Promise.all
同時獲取這三個promises。
有三個步驟:
- 建立三個promises
- 將三個promises新增到一個數組中
- 使用
Promise.all
來await
promises陣列
如下所示:
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() 複製程式碼

這就是你需要了解的基本非同步功能函式!我希望這篇文章為你掃除了些障礙。
筆記:這篇文章是Learn JavaScript的修改摘錄。如果你發現本文有用,你可能需要去檢視它。