天天看點

揭開 JavaScript 事件循環的神秘面紗

作者:千鋒IT教育
揭開 JavaScript 事件循環的神秘面紗

Javascript 是一種單線程語言,這意味着它一次隻能執行一個任務。但是,它仍然設法同時執行多項任務。它通過使用一些複雜的資料結構給人一種多線程的錯覺。為實作這一點,Javascript 引擎有一個稱為事件循環的重要元件。我們将了解什麼是事件循環以及它如何在不阻塞主線程的情況下處理異步任務。

什麼是事件循環?

事件循環是 Javascript 中的一種機制,可以執行非阻塞異步操作。它允許 Javascript 在不阻塞主線程的情況下處理諸如從伺服器擷取資料、發出 HTTP 請求和處理使用者事件等任務。

根據,它是一個運作時模型,它執行代碼,收集和處理事件,并執行排隊的子任務。了解事件循環的工作原理對于編寫高效和高性能的代碼至關重要。

為了更好地了解事件循環,讓我們列出用于執行異步代碼的元件 -

  1. 調用堆棧:JavaScript 使用調用堆棧來跟蹤目前正在執行的函數(執行上下文)。當一個函數被調用時,它被添加到堆棧中,當它傳回時,它被從堆棧中删除。
  2. Web API:Web API 由浏覽器或 JavaScript 運作時環境提供,并提供 DOM 操作、計時器(setTimeout、setInterval)、XMLHttpRequest 等功能。這些 API 異步處理耗時的任務。JavaScript 與 Web API 互動,例如 DOM API、XMLHttpRequest 或 setTimeout,它們提供 JavaScript 引擎之外的功能。
  3. 任務隊列:任務隊列(也稱為回調隊列)儲存準備好由事件循環處理的任務。當相關的異步操作完成時,這些任務就會入隊。異步操作,例如計時器、使用者事件和網絡請求,由 Web API 處理。一旦這些操作完成,它們就會被放入任務隊列中。
  4. 事件循環:事件循環不斷檢查兩件事:調用堆棧和任務隊列。如果 Call Stack 為空,則從 Task Queue 中取出第一個任務,并将其推送到 Call Stack 中執行。

通過代碼示例了解事件循環

console.log('Start');

setTimeout(function() {
  console.log('Inside setTimeout');
}, 0);

console.log('End');           

複制

在這裡,我們有 3 個控制台日志語句。但是其中一個控制台日志是在setTimeoutWeb API 中定義的。此 Web API 會将計時器設定為設定為setTimeout(此處我們已給出0ms)的值,一旦時間完成,setTimeoutWeb API 會将回調發送到任務隊列。現在,它會一直留在那裡直到郵件線程被釋放,也就是說,執行堆棧變空。

這裡需要注意的一點是,即使時間設定成0ms中的setTimeout,也會在最後執行。這是因為它setTimeout是一個帶有定時器的異步任務,必須進入隊列,然後等待主線程空閑。這個定時器可以是0 ms或10000 ms無論如何,它仍然會被注冊到任務隊列中。下面的可視化圖表清楚地解釋了這一點——

揭開 JavaScript 事件循環的神秘面紗

現在更清楚了,對吧?是以,這就是異步任務的工作方式。請注意,附加到 setTimeout 的時間是最小的,即代碼至少不會在設定的時間内運作。但是隻有在主線程釋放後才會執行。假設您有一個 1000 毫秒的 setTimeout,但由于執行了一些複雜的操作,主線程花費了 2000 毫秒。在這種情況下,注冊的 setTimeout 隻能在 2000 毫秒後執行,而不是在 1000 毫秒後立即執行!

讓我們深入研究下一個例子。我們将使用 XMLHttpRequest

console.log('Start');

var request = new XMLHttpRequest();
request.open('GET', 'https://api.example.com/data', true);
request.onreadystatechange = function() {
  if (request.readyState === 4 && request.status === 200) {
    console.log('Data received:', request.responseText);
  }
};
request.send();

console.log('End');           

複制

我希望從前面的例子中你已經解碼了上面的代碼是如何工作的。是的,Http 異步請求将由 Web API 處理XMLHttpRequest。它将被處理并發送到任務隊列中。Event Loop會一直等到主線程空閑,然後将任務Dqueue到Task Queue裡面,放到Execution Stack中,由主線程執行。通過這個解釋,我們可以說輸出将是 -

Start
End
Data received: xyz // xyz is any response that API has sent           

複制

結論

了解 JavaScript 事件循環對于編寫高效且響應迅速的 JavaScript 代碼至關重要。通過掌握其内部工作原理以及調用堆棧、Web API、任務隊列和事件循環等元件的作用,您可以自信地處理異步任務并建構高性能的 Web 應用程式。有了這些知識,您就可以很好地處理複雜的場景并充分利用 JavaScript 的異步特性

揭開 JavaScript 事件循環的神秘面紗

繼續閱讀