目錄
瀏覽器的Event Loop
Node.js 的Event loop
總結
首頁 web前端 js教程 探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

Jan 05, 2022 am 10:29 AM
node.js 瀏覽器

這篇文章帶大家去探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop,希望對大家有幫助!

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

Event Loop 是JavaScript 的基礎概念,面試必問,平常也常談到,但有沒有想過為什麼會有Event Loop,它為什麼會這樣設計的呢?

今天我們就來探索下原因。

瀏覽器的Event Loop

JavaScript 是用來實作網頁互動邏輯的,涉及dom 操作,如果多個執行緒同時操作需要做同步互斥的處理,為了簡化就設計成了單線程,但是如果單線程的話,遇到定時邏輯、網路請求又會阻塞住。怎麼辦呢?

可以加一層調度邏輯。把 JS 程式碼封裝成一個個的任務,放在一個任務佇列中,主執行緒就不斷的取任務執行就好了。

每次取任務執行,都會建立新的呼叫堆疊。

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

其中,計時器、網路請求其實都是在別的執行緒執行的,執行完了之後在任務佇列裡放個任務,告訴主執行緒可以繼續往下執行了。

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

因為這些非同步任務是在別的執行緒執行完,然後透過任務佇列通知下主線程,是一種事件機制,所以這個循環叫做 Event Loop。

這些在其他執行緒執行的非同步任務包括計時器(setTimeout、setInterval),UI 渲染、網路請求(XHR 或 fetch)。

但是,現在的 Event Loop 有個嚴重的問題,沒有優先順序的概念,只是按照先後順序來執行,那如果有高優先級的任務就得不到及時的執行了。所以,得設計一套插隊機制。

那就搞一個高優先權的任務佇列就好了,每執行完一個普通任務,都去把所有高優先權的任務給執行完,之後再去執行普通任務。

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

有了插隊機制之後,高優任務就能得到及時的執行。

這就是現在瀏覽器的 Event Loop。

其中普通任務叫做 MacroTask(巨集任務),高優任務叫做 MicroTask(微任務)。

巨集任務包含:setTimeout、setInterval、requestAnimationFrame、Ajax、fetch、script 標籤的程式碼。

微任務包括:Promise.then、MutationObserver、Object.observe。

怎麼理解宏微任務的分割呢?

計時器、網路請求這種都是在別的執行緒跑完之後通知主執行緒的普通非同步邏輯,所以都是巨集任務。

而高優任務的這三種也很好理解,MutationObserver 和Object.observe 都是監聽某個物件的變化的,變化是很瞬時的事情,肯定要馬上回應,不然可能又變了,Promise 是組織非同步流程的,非同步結束呼叫then 也是很高優的。

這就是瀏覽器裡的Event Loop 的設計:設計Loop 機制和Task 佇列是為了支援非同步,解決邏輯執行阻塞主執行緒的問題,設計MicroTask 佇列的插隊機制是為了解決高優任務儘早執行的問題。

但後來,JS 的執行環境不只是瀏覽器一種了,還有了 Node.js,它同樣也要解決這些問題,但是它設計出來的 Event Loop 更細緻一些。

Node.js 的Event loop

Node 是一個新的JS 運作環境,它同樣要支援非同步邏輯,包括計時器、 IO、網路請求,很明顯,也可以用Event Loop 那一套來跑。

但是呢,瀏覽器那套 Event Loop 就是為瀏覽器設計的,對於做高效能伺服器來說,那種設計還是有點粗糙了。

哪裡粗糙呢?

瀏覽器的 Event Loop 只分了兩層優先權,一層是巨集任務,一層是微任務。但是宏任務之間沒有再劃分優先級,微任務之間也沒有再劃分優先級。

而Node.js 任務巨集任務之間也是有優先權的,例如定時器Timer 的邏輯就比IO 的邏輯優先權高,因為涉及時間,越早越準確;而close 資源的處理邏輯優先權就很低,因為不close 最多多佔點記憶體等資源,影響不大。

於是就把巨集任務佇列拆成了五個優先權:Timers、Pending、Poll、Check、Close。

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

解釋這五種巨集任務:

Timers Callback: 牽涉到時間,肯定越早執行越準確,所以這個優先順序最高很容易理解。

Pending Callback:處理網路、IO 等異常時的回調,有的 *niux 系統會等待發生錯誤的回報,所以得處理下。

Poll Callback:處理 IO 的 data,網路的 connection,伺服器主要處理的就是這個。

Check Callback:執行 setImmediate 的回呼,特點是剛執行完 IO 之後就能回呼這個。

Close Callback:關閉資源的回調,晚點執行影響也不到,優先權最低。

所以呢,Node.js 的Event Loop 就是這樣跑的了:

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

還有一點不同要特別注意:

Node.js 的Event Loop 並不是瀏覽器那種一次執行一個宏任務,然後執行所有的微任務,而是執行完一定數量的Timers 宏任務,再去執行所有微任務,然後再執行一定數量的Pending 的巨集任務,然後再去執行所有微任務,剩餘的Poll、Check、Close 的巨集任務也是這樣。 (訂正:node 11 之前是這樣,node 11 之後改為了每個巨集任務都執行所有微任務了)

為什麼這樣呢?

其實按照優先權來看很容易理解:

假設瀏覽器裡面的巨集任務優先權是1,所以是按照先後順序依序執行,也就是一個巨集任務,所有的微任務,再一個宏任務,再所有的微任務。

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

而Node.js 的宏任務之間也是有優先權的,所以Node.js 的Event Loop 每次都是把目前優先權的所有巨集任務跑完再去跑微任務,然後再跑下一個優先順序的巨集任務。

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

也就是是一定數量的 Timers 巨集任務,再所有微任務,再一定數量的 Pending Callback 巨集任務,再所有微任務這樣。

為什麼說是一定數量呢?

因為如果某個階段巨集任務太多,下個階段就一直執行不到了,所以有個上限的限制,剩餘的下個 Event Loop 再繼續執行。

除了巨集任務有優先級,微任務也劃分了優先級,多了一個 process.nextTick 的高優先級微任務,在所有的普通微任務之前來跑。

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

所以,Node.js 的Event Loop 的完整流程就是這樣的:

  • Timers 階段:執行一定數量的定時器,也就是setTimeout、setInterval 的callback,太多的話留到下次執行
  • 微任務:執行所有nextTick 的微任務,再執行其他的普通微任務
  • Pending 階段:執行一定數量的IO 和網路的異常回調,太多的話留到下次執行
  • 微任務:執行所有nextTick 的微任務,再執行其他的普通微任務
  • Idle/Prepare 階段:內部用的一個階段
  • 微任務:執行所有nextTick 的微任務,再執行其他的普通微任務
  • Poll 階段:執行一定數量的檔案的data 回呼、網路的connection 回呼,太多的話留到下次執行。 如果沒有IO 回調並且也沒有timers、check 階段的回調要處理,就阻塞在這裡等待IO 事件
  • 微任務:執行所有nextTick 的微任務,再執行其他的普通微任務
  • Check 階段:執行一定數量的setImmediate 的callback,太多的話留到下次執行。
  • 微任務:執行所有nextTick 的微任務,再執行其他的普通微任務
  • Close 階段:執行一定數量的close 事件的callback,太多的話留到下次執行。
  • 微任務:執行所有nextTick 的微任務,再執行其他的普通微任務

比起瀏覽器裡的Event Loop,明顯複雜了很多,但經過我們之前的分析,也能理解:

Node.js 對巨集任務做了優先權劃分,從高到低分別是Timers、Pending、Poll、Check、Close 這5 種,也對微任務做了劃分,也就是nextTick 的微任務和其他微任務。執行流程是先執行完目前優先權的一定數量的巨集任務(剩下的留到下次迴圈),然後執行process.nextTick 的微任務,再執行普通微任務,之後再執行下個優先權的一定數量的宏任務。 。這樣不斷循環。其中還有一個 Idle/Prepare 階段是給 Node.js 內部邏輯用的,不需要關心。

改變了瀏覽器Event Loop 裡那種一次執行一個宏任務的方式,可以讓高優先級的宏任務更早的得到執行,但是也設定了個上限,避免下個階段一直無法執行。

還有一個特別要注意的點,就是poll 階段:如果執行到poll 階段,發現poll 隊列為空並且timers 隊列、check 隊列都沒有任務要執行,那麼就阻塞的等在這裡等IO 事件,而不是空轉。 這點設計也是因為伺服器主要是處理 IO 的,阻塞在這裡可以更早的回應 IO。

完整的Node.js 的Event Loop 是這樣的:

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

#對比下瀏覽器的Event Loop:

探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!

兩個JS 運行環境的Event Loop 整體設計思路是差不多的,只不過Node.js 的Event Loop 對宏任務和微任務做了更細粒度的劃分,也很容易理解,畢竟Node .js 面向的環境和瀏覽器不同,更重要的是服務端對效能的要求會更高。

總結

JavaScript 最早是用來寫網頁互動邏輯的,為了避免多執行緒同時修改dom 的同步問題,設計成了單線程,又為了解決單執行緒的阻塞問題,加了一層調度邏輯,也就是Loop 迴圈和Task 佇列,把阻塞的邏輯放到其他執行緒跑,從而支援了非同步。然後為了支援高優先權的任務調度,又引入了微任務佇列,這就是瀏覽器的 Event Loop 機制:每次執行一個巨集任務,然後執行所有微任務。

Node.js 也是一個JS 運行環境,想支援異步同樣要用Event Loop,只不過服務端環境更複雜,對效能要求更高,所以Node.js 對宏微任務都做了更細粒度的優先權分割:

Node.js 里分割了5 種巨集任務,分別是Timers、Pending、Poll、Check、Close。又劃分了 2 種微任務,分別是 process.nextTick 的微任務和其他的微任務。

Node.js 的Event Loop 流程是執行目前階段的一定數量的巨集任務(剩餘的到下個迴圈執行),然後執行所有微任務,一共有Timers、Pending、Idle/ Prepare、Poll、Check、Close 6 個階段。 (訂正:node 11 之前是這樣,node 11 之後改為了每個巨集任務都執行所有微任務了)

其中 Idle/Prepare 階段是 Node.js 內部用的,不用關心。

特別要注意的是Poll 階段,如果執行到這裡,poll 隊列為空並且timers、check 隊列也為空,就一直阻塞在這裡等待IO,直到timers、check 隊列有回調再繼續loop。

Event Loop 是JS 為了支援非同步和任務優先權而設計的一套排程邏輯,針對瀏覽器、Node.js 等不同環境有不同的設計(主要是任務優先權的劃分粒度不同),Node.js 面對的環境更複雜、對效能要求更高,所以Event Loop 設計的更複雜一些。

更多node相關知識,請造訪:nodejs 教學! !

以上是探索下瀏覽器和 Node.js 為什麼會這樣設計 EventLoop!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何通過CSS自定義resize符號並使其與背景色統一? 如何通過CSS自定義resize符號並使其與背景色統一? Apr 05, 2025 pm 02:30 PM

CSS自定義resize符號的方法與背景色統一在日常開發中,我們經常會遇到需要自定義用戶界面細節的情況,比如調...

如何在網頁上正確顯示本地安裝的'荊南麥圓體”? 如何在網頁上正確顯示本地安裝的'荊南麥圓體”? Apr 05, 2025 pm 10:33 PM

在網頁中使用本地安裝的字體文件最近,我從網上下載了一種免費字體,並成功將其安裝到了我的系統中。現在...

為什麼在Safari中自定義樣式表能在本地網頁生效,但在百度頁面上卻無法生效? 為什麼在Safari中自定義樣式表能在本地網頁生效,但在百度頁面上卻無法生效? Apr 05, 2025 pm 05:15 PM

在Safari中使用自定義樣式表的問題探討今天我們來探討一個關於Safari瀏覽器的自定義樣式表應用問題。前端新手...

Flex佈局下文字超出省略卻撐開容器?如何解決? Flex佈局下文字超出省略卻撐開容器?如何解決? Apr 05, 2025 pm 11:00 PM

Flex佈局下文字超出省略導致容器撐開的問題及解決方法在使用Flex...

為什麼Edge瀏覽器中的特定div元素無法顯示?如何解決這個問題? 為什麼Edge瀏覽器中的特定div元素無法顯示?如何解決這個問題? Apr 05, 2025 pm 08:21 PM

如何解決用戶代理樣式表導致的顯示問題?在使用Edge瀏覽器時,項目中的一個div元素無法顯示。經過查看,發�...

負邊距在某些情況下為何未生效?如何解決這個問題? 負邊距在某些情況下為何未生效?如何解決這個問題? Apr 05, 2025 pm 10:18 PM

負邊距為何在某些情況下未生效?在編程過程中,CSS中的負邊距(negative...

如何通過JavaScript或CSS控制瀏覽器打印設置中的頁首和頁尾? 如何通過JavaScript或CSS控制瀏覽器打印設置中的頁首和頁尾? Apr 05, 2025 pm 10:39 PM

如何使用JavaScript或CSS控制瀏覽器打印設置中的頁首和頁尾在瀏覽器的打印設置中,有一個選項可以控制是否顯�...

如何在網頁上使用本地安裝的字體文件? 如何在網頁上使用本地安裝的字體文件? Apr 05, 2025 pm 10:57 PM

如何在網頁上使用本地安裝的字體文件你是否在網頁開發中遇到過這樣的情況:你已經在自己的電腦上安裝了一...

See all articles