簡述JavaScript異步函數 async/await

ES7 引入的 async/await 是對 JavaScript 異步編程的一種改進,它提供了使用同步樣式代碼異步訪問資源的選項,而不會阻塞主線程。但是,要很好地使用它有點棘手。在本文中,將從不同的角度探索 async/await,并展示如何正確有效地使用它們。
async/await 好處
async/await 帶來的最重要的好處就是同步編程風格,先來看一個例子。
// async/await
const getArticlesByAuthorWithAwait = async (authorId) => {
const articles = await articleModel.fetchAll();
return articles.filter((b) => b.authorId === authorId);
};
// promise
const getArticlesByAuthorWithPromise = (authorId) => {
return articleModel
.fetchAll()
.then((articles) => articles.filter((b) => b.authorId === authorId));
};
很明顯,async/await 版本比 promise 版本更容易理解。如果忽略 await 關鍵字,代碼看起來就像任何其他同步語言,如 Python。
同時 async/await 有原生瀏覽器支持,截至目前,所有主流瀏覽器都已全面支持異步功能。
需要注意的是
async/await在使用的過程中需要成對出現,如在函數里面要使用await,就必須將函數定義為async。
async/await 可能會產生誤導
有些文章將 async/await 與 Promise 進行比較,并聲稱它是 JavaScript 異步編程發展的下一代,這一點個人覺得有點誤導,個人認為 async/await 是一種改進,一個語法糖,不會徹底改變編程風格。
本質上,異步函數仍然是 promises,在正確使用異步函數之前,必須了解 promises。
- Promise.any() 原理解析及使用指南
- Promise.all() 原理解析及使用指南
- Promise.race() 原理解析及使用指南
- Promise.allSettled() 原理解析及使用指南
async/await 陷阱
盡管 await 可以使代碼看起來像同步的,但請記住它們仍然是異步的,必須注意避免過于順序化。
const getArticlesAndAuthor = async (authorId) => {
const articles = await articleModel.fetchAll();
const author = await authorModel.fetch(authorId);
return {
author,
articles: articles.filter((article) => article.authorId === authorId),
};
};
這段代碼在邏輯上看起來是正確的,然而這是回產生誤解。
await articleModel.fetchAll()將等到fetchAll()返回。- 然后
await authorModel.fetch(authorId)將會被立即調用。
錯誤處理
使用 promise,異步函數有兩個可能的返回值:resolve 和 reject,以用于正常情況使用 .then() 和異常情況使用.catch()。然而,async/await 錯誤處理就不太好,需要使用 try...catch 來捕獲異常。
const getArticlesByAuthorWithAwait = async (authorId) => {
try {
const articles = await articleModel.fetchAll();
return articles.filter((b) => b.authorId === authorId);
} catch (error) {
// 錯誤處理
}
};
總結
async/await 非常強大,但也有一些注意事項。但是如果正確使用它們,還是有助于使代碼高效并且高可讀。