1. 程式人生 > >ES7 Async/Await 陷阱

ES7 Async/Await 陷阱

average 模式 時間 eth 復雜 簡化 同時 不同的 then

什麽是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 陷阱