JavaScript Async/Await
在很長一段時間裡,JavaScript 開發人員不得不依賴回撥來處理非同步程式碼。因此,我們中的許多人都經歷過回撥地獄,當面對這樣的函式時,我們會感到無賴
不過好在JavaScript提供了,.then()的一種回覆方式,目前也有很多人正在用他
現在,隨著 Async/Await 的最新增加,編寫 JavaScript 程式碼將會變得更加優雅!
什麼是 Async/Await?
Async/Await 是一個期待已久的 JavaScript 特性,它使得使用非同步函式變得更加愉快和更容易理解。它建立在 Promises 之上,並與所有現有的基於 promise 的 api 相容
這個名字來自 async 和 await ——這兩個關鍵詞可以幫助我們清理非同步程式碼:
Async-宣告一個非同步函式(Async function someName (){ ... })
- 自動地將一個普通的函式轉換成一個承諾
- 當呼叫非同步函式時,當非同步完成時,然後返回的是非同步內容
- 在非同步函式中允許使用await
Await-暫停 async 函式的執行
- 當被放置在一個Promise前時, 強制程式碼的其餘部分等待,直到承諾完成並返回結果
- 只對 Promises 起作用,對 callback 不起作用
- 只能在裡面使用async函式中使用
通過一個簡單的例子來分析
假設我們想從伺服器獲取一些 JSON 檔案。我們將編寫一個使用 axios 庫的函式,並向 https://tutorialzine.com/misc...
下面我們可以看到同一個函式實現了兩個。首先是使用 Promises,然後是第二個使用 Async/Await
// Promise function getJSON(){ // 為了使函式阻塞,我們手動建立一個承諾. return new Promise( function(resolve) { axios.get('https://tutorialzine.com/misc/files/example.json') .then( function(json) { // 在.then中獲得返回的json資料 // 我們使用resolve返回結果 resolve(json); }); }); } // Async/Await // async關鍵字將自動建立一個新的Promise並返回它. async function getJSONAsync(){ // await關鍵字使我們不必編寫then(). let json = await axios.get('https://tutorialzine.com/misc/files/example.json'); // GET請求的結果在json變數中可用. // 獲取資料就像在一個常規的同步函式中一樣 return json; }
很明顯,Async/Await 版本的程式碼更短,更容易閱讀。除了使用的語法之外,這兩個函式完全相同——它們都返回 Promises 並使用 axios 的 JSON 響應解析。我們可以這樣呼叫我們的 async 函式:
async返回本身就是一個Promise
getJSONAsync().then( function(result) {
// Do something with result.
});
Async/Await 會使承諾過時嗎?
不,一點也不。
在使用 Async/Await 時,我們仍然在引擎蓋下使用 Promises。
從長遠來看,充分理解Promise
實際上會對你有所幫助,因此強烈推薦你這麼做
甚至在一些情況下 Async/Await 也不能解決問題,我們不得不回到 Promises 尋求幫助。其中一種情況是,我們需要進行多個獨立的非同步呼叫,並等待它們全部完成
如果我們嘗試使用 async 和 await 來實現這個功能,將會發生以下情況:
async function getABC() {
let A = await getValueA(); // getValueA 需要2秒
let B = await getValueB(); // getValueB 需要4秒
let C = await getValueC(); // getValueC 需要3秒
return A*B*C;
}
每個await等待都將等待await前一個返回結果。因為我們一次只調用一個函式,整個函式從開始到結束(2 + 4 + 3)需要9秒
這不是最佳解決方案,因為三個變數 a、 b 和 c 並不相互依賴。換句話說,在得到 b 之前,我們不需要知道 a 的值。我們可以在同一時間得到它們,減少幾秒鐘的等待時間
在同一時間傳送所有請求。這將確保我們在繼續之前仍然擁有所有的結果,但是非同步呼叫將並行請求,而不是一個接一個地請求
async function getABC() {
// Promise.all()允許我們同時傳送多個請求,型別是個陣列
let results = await Promise.all([ getValueA, getValueB, getValueC ]);
return results.reduce((total,value) => total * value);
}
這樣一來,函式執行的時間就會少得多。getValueA 和 getValueC 呼叫在 getValueB 結束時已經完成,將有效地將執行時間減少到最慢的請求的時間(getValueB-4秒) ,而不是總和
Async/Await 中的錯誤處理
Async/Await 的另一個優點是,它允許我們在一個很好在 try/catch 塊中捕捉任何意外的錯誤。只需要像這樣包裝下Await:
async function doSomethingAsync(){
try {
// 這裡非同步可能會發送失敗
let result = await someAsyncCall();
}
catch(error) {
// 如果失敗了,通過catch捕捉到錯誤
}
}
Catch 子句將處理等待的非同步呼叫或者我們在 try 塊中編寫的任何其他失敗程式碼所引發的錯誤
如果情況需要,我們還可以在執行 async 函式時捕獲錯誤。因為所有的非同步函式都返回 Promises,我們可以簡單地包含一個。在呼叫 catch ()事件處理程式時。
async function doSomethingAsync(){
// This async call may fail.
let result = await someAsyncCall();
return result;
}
// 後面更用catch捕獲錯誤
doSomethingAsync().
.then(successHandler)
.catch(errorHandler);
總結
隨著 Async/Await 的加入,JavaScript 語言在程式碼可讀性和易用性方面取得了巨大的飛躍。編寫類似於常規同步函式的非同步程式碼的能力將受到初學者、 JavaScript 開發者和資深編碼者的青睞