ES7 Async/Await 陷阱
什麽是Async/Await
ES6新增了Promise函數用於簡化項目代碼流程。然而在使用promise時,我們仍然要使用callback,並且並不知道程序要幹什麽,例如:
function doSomething() {
let i = 0;
waitOneSecond() // 返回一個Promise對象
.then(() => console.log(i));
i = 5;
}
最終console.log(i) 的結果是5,並不是0
為此,ES7引入了async函數,前面的例子可以改寫這樣:
async function doSomething() {
let i = 0;
await waitOneSecond();// 等待1秒
console.log(i);
i = 5;
}
這段代碼片段中console.log(i)的結果是0。其中關鍵字await停止當前函數的執行,直到waitOneSecond()返回的promise對象狀態變更為fulfilled(完成),並產生其返回值。
當返回的promise對象的狀態變更為rejected(失敗),錯誤信息會被 try/catch 代碼塊所捕獲。
常見陷阱
效率損失:
亂用async/await,可能導致低效的設計模式。例如,假設我們想從數據庫中獲得一些用戶他們的年齡平均。我們會這樣做的:
async function getUserAge(userId) {
await waitOneSecond();// 等待1秒
return 7;
}
async function getAverageAge(userIds) {
let sumOfAges = 0;
let numOfUsers = userIds.length;
for (let userId of userIds) {
sumOfAges += await getUserAge(userId);
}
return sumOfAges / numOfUsers;
}
顯而易見,這是錯誤的,假設我們有5個用戶,上面的代碼片段會輪訓所有的用戶並且等待每一個單獨調用數據庫,所以最終整個函數的等待時間是5秒。
為了更好的性能,降低等待時間,修改如下:
async function getAverageAge(userIds) {
let sumOfAges = 0;
let numOfUsers = userIds.length;
let agesPromises = userIds.map(getUserAge);//將每個用戶對應的promise對象封裝到數組中
let ages = await Promise.all(agesPromises);//使用Promise.all調用
for (let age of ages) {
sumOfAges += age;
}
return sumOfAges / numOfUsers;
}
修改之後,代碼變得復雜了一些,但是所有的數據庫調用,都是同時進行的。無論你有多少用戶,這個方法的等待時間只需要1秒。
在使用async/await函數時,當函數體內需要使用await多次調用外部函數並且函數返回值彼此無依賴關系時,使用Promise.all降低函數整體的等待時間。
變量汙染:
當使用async函數時,會令代碼更易閱讀,但是他們並不是真正的將你的代碼變為同步,只是promise的語法糖而已,看下面這個例子
let currentUserId = 0;
async function getInfoAboutUser() {
currentUserId++; // 令每個用戶id均唯一
let data = await waitTenSeconds(); // 獲取某些其他數據,等待時間10秒
return { id: currentUserId , data };
}
async function registerUser() {
let user = await getInfoAboutUser();
await storeUser(user);
}
現在假設,有2個不同的用戶接連註冊,getInfoAboutUser 函數將被接連執行,當10秒的等待時間結束後,2個用戶的id都是相同的。
在這個例子中,我們可以很簡單的避免這個問題:
async function getInfoAboutUser() {
let data = await waitTenSeconds(); // 獲取某些其他數據,等待時間10秒
currentUserId++; //令每個用戶id均唯一
return { id: currentUserId };
}
結語
async/await函數的出現,極大的提高了javascript代碼的可讀性,但是他們並不是魔法,依然有很多未知的問題等待我們去發現。
我希望你喜歡這篇文章,並認為它遊泳。如果有其他的陷阱,或者有任何疑問,請在評論中讓我知道
ES7 Async/Await 陷阱