一、瀏覽器進程?
早期的瀏覽器是單進程的,所有功能雜糅在一個進程中;現在的瀏覽器是多進程的,包含瀏覽器進程、網絡進程、渲染進程等等,每個進程負責的工作不同。
- 瀏覽器進程:負責界面顯示(地址欄、書簽、歷史記錄)、窗口管理、標簽頁的創建和銷毀、用戶交互。
- 網絡進程:負責加載網絡資源,HTTP請求等。
- 渲染進程:負責執行HMTL、CSS、JS代碼。每一個頁面都會有一個或多個獨立的渲染進程。
#瀏覽器對象模型(Browser Object Module, BOM)交互主要依賴瀏覽器進程。文檔對象模型(Document Object Module ,DOM)主要依賴渲染進程。
還有一些其他的輔助進程,如GPU進程等。
在瀏覽器"自定義及控制"??"更多工具"??"任務管理器"查看瀏覽器進程情況:
二、渲染進程的渲染主線程和消息隊列
渲染主線程
前端工程師編寫的HTML格式文件代碼由渲染進程負責解析最終繪制在頁面上。
在這個過程中,渲染主線程是最繁忙的線程,其需要處理任務包括:
- 解析HTML
- 解析CSS
- 計算樣式
- 布局
- 處理圖層
- 每秒渲染頁面60次(60幀)
- 執行全局JS代碼
- 執行封裝成任務的事件處理和計時器回調函數等
渲染主線程的任務多、任務頻繁,其依賴消息隊列(message queue,或事件隊列)機制,先進先出原則調度任務。
任務源來自:1??渲染主線程正在執行的任務產生的新任務,如JS代碼運行產生的各種?2??其他線程向消息隊列遞交的新任務,如網絡請求、用戶交互等。
消息隊列的演變:宏/微任務隊列??多任務隊列
本章節關于事件循環中隊列和隊列優先級的內容。
瀏覽器的任務沒有優先級,但消息隊列有優先級。
傳統將消息隊列簡單分為宏任務隊列和微任務隊列。
但瀏覽器逐漸復雜,在最新W3C標準下,瀏覽器不再有宏隊列的說法,每個任務都有一個任務類型,在一次事件循環中,由瀏覽器自行決定哪一個隊列的任務(瀏覽器真實的使用環境是復雜多變的)。但瀏覽器必須包含一個微隊列,微隊列的任務一定具有最高優先級,必須優先調度。
在目前Chrome的實現中,與前端開發最相關的隊列,至少包含了以下幾個:
- 延時隊列:用于存放計時器到時后的回調函數「中」。(setTimeOut、setInternel)
- 交互隊列:用于存放用戶操作后產生的時間處理函數「高」。(addEventListener)
- 微隊列:用于存放需要最快執行的任務,優先級「最高」。(Promise.then)
面經總結
Q:為什么JavaScript是異步的?
A:從渲染主線程、同步的劣勢和異步操作過程等角度回答。
- JS的運行環境JS是單線程的語言,這是因為它運行在瀏覽器渲染進程中的渲染主線程,渲染主線程只有一個。渲染主線程是瀏覽器線程里最繁忙的一個,承擔了許多工作,解析HTML、解析CSS、計算樣式、布局、處理圖層、每秒渲染頁面60次(60幀)、執行全局JS代碼、封裝成任務的事件處理和計時器回調函數(選幾個回答)等都在其中執行。
- 如果使用同步的方式,極有可能會造成渲染主線程的阻塞,從而導致消息隊列中的很多其他任務無法執行。這樣一方面會導致主線程阻塞等待白白消耗時間,另一方面導致頁面無法及時更新,給用戶造成頁面卡死現象。
- 所以瀏覽器采用異步的方式,具體做法是當某些任務發生時,比如計時器、網絡請求、事件監聽,主線程將任務分發交給其他線程去處理,自身立即結束該任務的執行,轉而執行后續代碼,當被轉發任務的線程完成時,將事先傳遞的回調函數包裝成任務加入到消息隊列的末尾排隊,等待主線程調度執行。在這種異步的模式下,瀏覽器用不阻塞,從而最大限度保證了單線程的流程運行。
Q:如何理解JavaScript中的事件循環?
A:事件循環也叫消息循環,是渲染主線程的工作方式。它幫助渲染主線程從不同優先級的隊列中循環調度任務執行。傳統將消息隊列簡單分為宏任務隊列和微任務隊列。但瀏覽器逐漸復雜,在最新W3C標準下,瀏覽器不再有宏隊列的說法,每個任務都有一個任務類型,在一次事件循環中,由瀏覽器自行決定哪一個隊列的任務(瀏覽器真實的使用環境是復雜多變的)。但瀏覽器必須包含一個微隊列,微隊列的任務一定具有最高優先級,必須優先調度。
練習題,閱讀代碼,寫出控制臺輸出字母順序:
1.
2.?
3.?
答案:
第一題:2 1
第二題:3 2 1
第三題:5 4 3 1 2