瀏覽器詳解

1 瀏覽器結構

圖片描述

瀏覽器分爲如下7個部分:javascript

  • 用戶界面
  • 瀏覽器引擎:在用戶界面和呈現引擎之間傳送指令。
  • 渲染引擎:也稱爲呈現引擎/瀏覽器內核,負責顯示請求的內容。
不一樣的瀏覽器有不一樣的呈現引擎,例如:
Chrome: Blink。Blink是Webkit的一個分支,添加了一些優化新特性。
Safari: Webkit
Firfox: Gecko
IE: Trident
  • 網絡:用於網絡調用,好比 HTTP 請求。
  • 用戶界面後端:用於繪製基本的窗口小部件,好比組合框和窗口。
  • JavaScript 解釋器:用於解析和執行 JavaScript 代碼。又稱爲 JavaScript 引擎,也能夠成爲 JavaScript 內核,在線程方面又稱爲 JavaScript 引擎線程。
一樣不一樣的瀏覽器有不一樣的JS解釋器,例如:
Chrome: V8引擎。以前是機器碼,最近重回字典碼
Safari: JavaScriptCore引擎
Firfox: Ion引擎
PS:不一樣瀏覽器間引擎性能差距不大,詳見 https://arewefastyet.com
  • 數據存儲:這是持久層。瀏覽器須要在硬盤上保存各類數據,例如 Cookie。

2 瀏覽器佔比

2.1 PC瀏覽器佔比

2018年2月份佔比
圖片描述html

2.2 移動瀏覽器佔比

圖片描述

3 渲染引擎詳解

瀏覽器渲染引擎最重要的工做就是將 HTML 和 CSS 文檔解析組合最終渲染到瀏覽器窗口上。以下圖所示:
圖片描述前端

解析 HTML 構建 DOM 樹時渲染引擎會將 HTML 文件的便籤元素解析成多個 DOM 元素對象節點,而且將這些節點根據父子關係組成一個樹結構。同時 CSS 文件被解析成 CSS 規則表,而後將每條 CSS 規則按照「從右向左」的方式在 DOM 樹上進行逆向匹配,生成一個具備樣式規則描述的 DOM 渲染樹。接下來就是將渲染樹進行佈局、繪製的過程。首先根據 DOM 渲染樹上的樣式規則,對 DOM 元素進行大小和位置的定位,關鍵屬性如position;width;margin;padding;top;border;...,接下來再根據元素樣式規則中的color;background;shadow;...規則進行繪製。

另外,這個過程是逐步完成的,爲了更好的用戶體驗,渲染引擎將會盡量早的將內容呈現到屏幕上,並不會等到全部的 html 都解析完成以後再去構建和佈局 render 樹。它是解析完一部份內容就顯示一部份內容,同時,可能還在經過網絡下載其他內容。java

再者,須要注意的是,在瀏覽器渲染完首屏頁面後,若是對 DOM 進行操做會引發瀏覽器引擎對 DOM 渲染樹的從新佈局和從新繪製,咱們叫作「重排」和「重繪」,因爲重排和重繪是先後依賴的關係,重繪發生時未必會觸發渲染引擎的重排,可是若是發生了重排就必然會觸發重繪操做,這樣帶來的性能損害就是巨大的。所以咱們在作性能優化的時候應該遵循「避免重排;減小重繪」的原則。[1]git

圖片描述

4 瀏覽器的進程與線程

4.1 瀏覽器的進程

在瀏覽器剛被設計出來的時候,那時的網頁很是的簡單,每一個網頁的資源佔有率是很是低的,所以一個進程處理多個網頁時可行的。而後在今天,大量網頁變得日益複雜。把全部網頁都放進一個進程的瀏覽器面臨在健壯性,響應速度,安全性方面的挑戰。由於若是瀏覽器中的一個tab網頁崩潰的話,將會致使其餘被打開的網頁應用。另外相對於線程,進程之間是不共享資源和地址空間的,因此不會存在太多的安全問題,而因爲多個線程共享着相同的地址空間和資源,因此會存在線程之間有可能會惡意修改或者獲取非受權數據等複雜的安全問題。
所以Chrome瀏覽器針對每個tab頁籤,都開了一個進程。github

4.2 瀏覽器的線程

瀏覽器的內核是多線程的,它們在內核控制下相互配合以保持同步,一個瀏覽器大概會有如下幾個線程:JavaScript引擎線程,GUI渲染線程(又稱爲UI主線程),瀏覽器事件觸發線程,異步 HTTP 請求線程(Chrome最多併發6個)web

JavaScript引擎是基於事件驅動單線程執行的,JavaScript引擎一直等待着任務隊列中任務的到來,而後加以處理,瀏覽器不管何時都只有一個JavaScript線程在運行JavaScript程序。segmentfault

var isEnd = true;
window.setTimeout(function () {
    isEnd = false;//1s後,改變isEnd的值
}, 1000);
//這個while永遠的佔用了js線程,因此setTimeout裏面的函數永遠不會執行
while (isEnd);

GUI渲染線程負責渲染瀏覽器界面,當界面須要重繪(Repaint)或因爲某種操做引起迴流(Reflow)時,該線程就會執行。但須要注意,GUI渲染線程與JavaScript引擎是互斥的,當JavaScript引擎執行時GUI線程會被掛起,GUI更新會被保存在一個隊列中等到JavaScript引擎空閒時當即被執行。後端

<script>
    btn.onclick=function() {
        div.style.height="900px"; //爲何不先到900而後在到100px?
        div.style.height="100px";
    }
</script>

事件觸發線程,當一個事件被觸發時,該線程會把事件添加到待處理隊列的隊尾,等待JavaScript引擎的處理。這些事件可來自JavaScript引擎當前執行的代碼塊如setTimeout、也可來自瀏覽器內核的其餘線程如鼠標點擊、Ajax異步請求等,但因爲JavaScript的單線程關係,全部這些事件都得排隊等待JavaScript引擎處理(當線程中沒有執行任何同步代碼的前提下才會執行異步代碼)。[2]瀏覽器

console.log(1)
setTimeout(function() {
    console.log(2)
}, 0)
console.log(3) // 輸出結果1,3,2

圖片描述

4.3 開啓額外的線程-Web Worker

以下圖,耗時JS的同步加載會阻攔頁面的渲染,這時候若是有一個線程能夠處理這個耗時js就行了。Web Worker能夠建立一個新的進程,來和UI主線程併發運行。可是這個新進程不能操做Dom對象, 只能用來處理複雜的JS的操做。

<html>
<script src="耗時.js"></script>
<body>
    <div>123</div>
</body>
</html>

使用方法:

// main.js
var worker = new Worker("task.js");
worker.postMessage(
        {
            id:1,
            msg:'Hello World'
        }
);
worker.onmessage=function(message){
    var data = message.data;
    console.log(JSON.stringify(data));
    worker.terminate();
};
worker.onerror=function(error){
    console.log(error.filename,error.lineno,error.message);
}
// task.js
onmessage = function(message){
    var data=message.data;
    data.msg = 'Hi from task.js';
    postMessage(data);
}

能夠看到,兩個js之間經過事件通信。儘管Web Worker在大量數據的檢索、數據運算上能提供一些幫助,可是使用面仍是比較窄的。

5 頁面加載優化

《雅虎前端優化35條規則翻譯》
《優化JavaScript執行》

相關文章
相關標籤/搜索