javascript
深入理解JavaScript的事件循环
最近閱讀《高性能JavaScript》時,第六章談到“通過定時器將JavaScript執行代碼的控制權先讓給瀏覽器用于更新UI狀態,然后再將控制權交回給JavaScript代碼,這樣就可以使得頁面更為流暢”,就聯想到了之前理解的事件循環。
這篇文章就是為了解釋為什么這么做可以提升頁面的流暢度。
事件循環(Event Loop)
單線程的JavaScript
總所周知,JavaScript語言的一大特點就是單線程,也就是說在一個時間段里,JavaScript只能做一件事情(瀏覽器是多線程)。 多線程可以實現應用的并行處理,從而以更高的CPU利用率提高整個應用程序的性能和吞吐量。
但是JavaScript卻以單線程進行,為什么呢?
JavaScript是瀏覽器腳本語言,用于與用戶交互以及操作DOM。 考慮如下情況,如果有兩個并發的操作,對同一個DOM節點分別進行刪除和修改樣式,此時瀏覽器就無法決定到底采用哪個線程的操作。類似數據庫,我們可以采用“鎖”來處理并發,但是這會平添復雜度。所以,JavaScript語言沒有支持多線程操作。 那又考慮這種情況,既然JavaScript是單線程,在某一時刻內只能執行特定的一個任務,并且會阻塞其它任務執行。那么如果用戶觸發了一個非常耗時的I/O操作,那么按道理后續的所有操作都得等到I/O操作完成后方可進行。但是,事實上,后續的任務不必等待這個耗時的I/O操作完成,原因就是JavaScript與生俱來的異步和回調。
而這背后恰好就是本文的主題——————事件循環
定義
事件循環包含了至少兩個任務隊列,宏任務隊列和微任務隊列。
宏任務
宏任務包含創建文檔對象、解析HTML、執行主線JavaScript代碼、更改當前URL以及各種事件,例如頁面加載、輸入、網絡事件和定時器等等。宏任務運行完成后,瀏覽器繼續其他的任務調度,如重新渲染頁面或者垃圾回收。
微任務
微任務包括promise、回調函數、DOM發生變化等。微任務更新應用程序的狀態,必須在瀏覽器任務繼續執行其他任務(渲染UI視圖或者進行下一個宏任務)之前執行。
兩個基本原則
?
在微任務隊列清空后,事件循環會檢查當前是否需要重新渲染UI,如果需要則渲染UI視圖。
補充
前情回顧
現在,用事件循環和簡單的例子來分析《高性能的JavaScript》中的那句話。 需求:給包含1000個數字的數組中的每個元素取絕對值(假設對一個數字進行需求操作耗時1ms)。
情況1(不使用定時器): 由于JavaScript主線程代碼屬于宏任務的一種,所以一次事件循環需要處理1000個數字,所以1s事件循環才進行到UI更新階段,但是由于耗時過長,UI狀態不會被更新,頁面出現卡頓甚至堵塞。
情況2(使用定時器): 將一次處理1000個數字的任務分割為20個每次處理50個數字的任務。由于定時器是宏任務的一種,所以一次事件循環只處理50個數字,由于此時微任務隊列為空,所以50ms后事件循環進行到UI更新階段,然后根據情況進行UI渲染,頁面未出現卡頓或者堵塞。
當然,如果只是單純的處理數據,我們可以考慮使用Web Workers。
總結
轉載于:https://www.cnblogs.com/LianML/p/9244729.html
總結
以上是生活随笔為你收集整理的深入理解JavaScript的事件循环的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: git+jekyll部署备忘
- 下一篇: 数组字典