前言
在前端面試中,往往會有一個非常經典的面試題,從瀏覽器地址欄輸入地址,並敲下回車後會發生什麼?這是一個非常寬泛、考察知識廣度和深度的題目。還記得最開始回答這個問題時,首先想到的是DNS解析-> 請求數據 -> HTML解析、CSS解析 -> 構造DOM樹 -> 構造渲染樹 -> 瀏覽器根據渲染樹進行渲染,將頁面展示到瀏覽器界面上。後來接觸了winter老師的重學前端的課程,對HTML、CSS解析又有了更深的認識,這個過程主要是通過詞法、語法分析來構造DOM樹和渲染樹。今天我想從瀏覽器入手來回答我們一開始的問題。
瀏覽器是多進程
不知道大家有沒有思考過這個問題,瀏覽器是多進程的,在Chrome瀏覽器中,設置->更多工具->任務管理器中,可以看到瀏覽器中有很多個進程。
可以看到這裏面有一個名叫瀏覽器的進程,一個GPU進程,兩個實用進程,多個標籤頁進程,多個擴展程序進程,這些進程分別是做什麼呢?下面我們來分析這些進程。
主進程
瀏覽器的主控進程,每個瀏覽器中僅有一個主控進程,對應上面截圖中的 瀏覽器進程。
主要負責:
- 網絡資源的下載;
- 頁面的展示與用戶交互;
- 協調各個進程,創建/銷燬頁面進程。
GUP進程
主要負責3D繪製,每個瀏覽器最多一個GPU進程。
渲染進程
這是瀏覽器每個TAB對應的進程,每一個TAB頁都是一個渲染進程,該進程負責HTML、CSS解析和DOM樹構造、渲染樹構造,計算元素位置等頁面渲染工作,以及JS腳本執行和事件處理過程。
這個進程是整個過程的核心處理過程,該進程中包括了多個線程來處理整個渲染過程。
GUI渲染線程
該線程主要做以下事情:
1. 解析HTML
2. 解析CSS
3. 構造DOM樹和SOM樹
4. 佈局和繪製
該線程與JS引擎線程是互斥的,當有JS引擎線程在執行時,該線程就會被掛起,所以當某個JS處理時間很長時,一般會出現頁面卡頓現象。
JS引擎線程
這個線程應該是我們比較熟悉的了,它是來執行我們的JS代碼的。這個過程可能會與時間處理線程、異步請求線程以及定時器觸發器線程並行進行。後面再整體舉例子來講。並且該線程是單線程的,所有其他線程的處理需等到該線程空閒時纔會執行。
事件處理線程
事件處理線程是實現事件循環的一個專門線程,主要是來處理像setTimeout、ajax請求、點擊事件等的專門的線程,爲了讓JS引擎線程專注得做一件事,該線程會維護一個事件隊列。
當有像上述的一些JS時,會在滿足條件後,將對應的任務放置到事件隊列中,直到JS引擎線程空閒時,纔會執行任務,執行任務的過程涉及到事件循環機制了。
異步請求線程
該線程應該就是來處理像Ajax一類的異步請求,若代碼中有異步請求的過程,瀏覽器會創建一個異步請求線程,該線程監聽XMLHTTPRequest對象的狀態,若狀態變更時有對應的回調函數,就會將回調函數給事件處理線程,事件處理線程將其放置到事件隊列中,等到JS引擎線程空閒時,按照事件循環機制執行。
定時器觸發器線程
該線程就是來處理setTimeout和setInterval這類操作了,若有這些過程,定時器線程會進行計時,當計時滿足條件之後,會將回調函數給事件處理線程,事件處理線程會將其放置到事件隊列中,等到JS引擎空閒時,按照事件循環機制執行。
第三方插件進程
該進程主要是擴展程序對應的進程,在擴展程序被啓用時,纔會有對應的進程。每種擴展程序對應一個插件進程。沒錯,上圖中的Vimium、windows Resizer和網頁截圖註釋是我瀏覽器中安裝的擴展程序。
瀏覽器各進程如何通信
知道了瀏覽器是多進程的,那麼瀏覽器各個進程是如何進行交互的呢?當我們打開瀏覽器,應該是主進程來接收的,那主進程是如何與每個TAB頁的渲染進程進行通信的,整個瀏覽器的處理流程是怎樣的?
當用戶從瀏覽器發起請求時:
- 瀏覽器主控進程請求頁面內容,然後通過一個RenderHost接口將信息發給渲染進程;
- 渲染進程通過Render接口拿到信息之後,進行一些解釋和處理,然後由GUI渲染線程進行渲染;
- 渲染線程主要來解析HTML、CSS以及構造DOM樹等,CSS資源的下載等需要主進程來進行網絡請求,也可能需要GPU進程來協助。當然,過程可能會遇到JS,此時也需要JS引擎線程來處理,如果有異步的任務,還需要事件處理線程來做。
- 當所有渲染工作做完之後,渲染進程會將結果反饋給瀏覽器主進程,主進程將結果進行繪製。
這應該就是在瀏覽器回車之後,瀏覽器的一系列操作,希望本文可以讓大家有個大概的瞭解和認識。