簡體   English   中英

異步等待 - 等待會阻止其他代碼運行嗎?

[英]Async await - does await block other code from running?

在 javascript 中,是否等待塊代碼? 例如,假設我們有以下代碼:

async function queryDB() {
    const addUser = await promisePool.execute("INSERT INTO Users (User) VALUES ('username')")
    const selectUser = await promisePool.execute("SELECT User FROM Users") 
}

“selectUser”會等到 addUser 完成后再運行,以便我們可以 select 添加的用戶?

另外,假設我們在不是 promise 的等待之間添加了一些代碼,如下所示:

    async function queryDB() {
        const addUser = await promisePool.execute("INSERT INTO Users (User) VALUES ('username')")

setTimeout(() => console.log('Do something that takes 3 seconds'), 3000);

        const selectUser = await promisePool.execute("SELECT User FROM Users") 
    }

“selectUser”會等待 addUser 而不是 setTimeout? 如果是這樣,您將如何編寫上述代碼以使 addUser 先運行,然后 setTimeout 再運行 selectUser?

我還想補充一點,我一直在研究和閱讀 stackoverflow 和其他資源,但我需要澄清一下。

“selectUser”會等到 addUser 完成后再運行,以便我們可以 select 添加的用戶?

來自MDN Docs - await:

await 表達式會導致異步 function 執行暫停,直到 Promise 被解決(即完成或拒絕),並在完成后恢復異步 function 的執行。 恢復時,await 表達式的值是已實現的 Promise 的值。

queryDB function 的執行將暫停,同時等待第一個 promise 解決。 第二行代碼只有在第一行代碼成功完成后才會執行。

“selectUser”會等待 addUser 而不是 setTimeout?

對,那是正確的。

如果是這樣,您將如何編寫上述代碼以使 addUser 先運行,然后 setTimeout 再運行 selectUser?

您可以將setTimeout包裝在返回 promise 的 function 中,然后等待 promise 以確保最后一行在前兩行完成后執行。

以下是包裝setTimeout的包裝器 function 的示例

function waitForTimeout(seconds) {
  return new Promise((resolve, reject) => {
     setTimeout(() => { 
        console.log("Hello World");
        resolve();
     }, seconds * 1000);        
  });
}

一旦你有一個包裝器 function,你可以await它,如下所示:

async function queryDB() {
    const addUser = await promisePool.execute(
        "INSERT INTO Users (User) VALUES ('username')"
    );

    await waitForTimeout(3);    // wait for 3 seconds

    const selectUser = await promisePool.execute("SELECT User FROM Users") 
}

簡短的回答是肯定的,它會阻塞。 await 的目的是確保您在下一行中有可用的結果。 因此,如果您需要 addUser 的值來進行下一個查詢,您將擁有它。

引入了它,因此您不必在第一行的末尾編寫 then() 並將第二次調用放入回調中,這會使代碼難以閱讀。

“selectUser”會等到 addUser 完成后再運行,以便我們可以 select 添加的用戶?

是的。

“selectUser”會等待 addUser 而不是 setTimeout? 如果是這樣,您將如何編寫上述代碼以使 addUser 先運行,然后 setTimeout 再運行 selectUser?

"selectUser" 將在 "addUser" 之后執行,而不是 setTimeout 回調。 如果要在 setTimeout 之后運行“selectUser”,可以將其添加到 setTimeout 回調 function 中。 所以它應該看起來像:

 async function queryDB() { const addUser = await promisePool.execute("INSERT INTO Users (User) VALUES ('username')") setTimeout(async () => { const selectUser = await promisePool.execute("SELECT User FROM Users"); }, 3000); }

重要提示: blocks在這里可能是一個壞詞。 一個更好的詞是它等待 更好的做法可能是只說使用await語法完成的操作保證按順序執行。

大局

在 Node 中使用異步代碼的主要原因是我們在等待一些異步操作(如數據庫請求、網絡請求、文件操作等)時不會阻塞整個應用程序——我們只會阻塞這個特定的執行上下文。

盡管 Node.js 只使用一個線程來執行用戶代碼,但是 I/O 操作是異步的並且它們是非阻塞的

因此,假設您有一個端點,其中包含您上面提供的代碼,該端點鏈接到前端的某個按鈕“添加用戶”。

  • 比爾按下按鈕,你開始處理請求,開始等待addUser操作
  • 此時約翰也按下了相同的按鈕。 您的代碼仍將被執行,並且也將開始等待直到addUser完成。
  • 假設Users表陷入死鎖,任何數據庫操作都會非常慢,我們還有第三個用戶 Jane,她只是在瀏覽您的網站,但她不需要登錄/注冊,所以她不碰Users表。 怎么了? Jane 完全沒問題,她的請求將 go 通過,沒有任何問題。

如何等待 setTimeout

setTimeout來自“上一個時代”,因此它使用回調而不是 async/await 語法。 但是,如果需要,始終可以將回調樣式轉換為 async/await。

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
await delay(5000);

簡而言之,await 只會阻塞當前異步 function 中 await 語句之后的代碼,而不是整個線程。 一旦等待被解決,代碼的 rest 就會被執行。 在您的示例中,由於您有 2 個 await 語句,因此在第一個語句完成之前,第二個語句不會運行,因為第一個語句阻塞了兩個 await 語句都在其中的 function 。 對於第二個示例,由於setTimeout()不返回 promise 並且您也不在等待它,因此 function 會將其視為“同步”操作。 也就是說,它會將setTimeout()回調扔到調用堆棧中,直到下一個事件循環並繼續執行下一行,這是另一個等待語句,它將再次阻塞 function 直到它被解決。

為了一一執行所有三行,您必須將setTimeout()放入 promise 並等待它,以便 JS 將其視為異步操作並“等待”它完成,然后再繼續下一個線。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM