瀏覽器是多進程模型。chrome瀏覽器主要包括如下進程類型javascript
進程模型有如下特徵:html
經過chrome瀏覽器右上角的三個點--More Tools--Task Manager能夠查看當前瀏覽器所開啓的進程。注:三個tab共享一個進程的狀況是在第一個Tab打開了另外兩個tabjava
每個進程內部,都有不少線程。web
Browser進程下有不少線程:chrome
其中線程1 Chrome是主線程。Chrome IOThread線程就是IO線程。中間還有用來處理視頻、存儲、王闊、文件、音頻、瀏覽歷史等的線程。canvas
Render進程下有如下線程瀏覽器
其中線程Chrome是主線程,Chrome IOThread線程就是IO線程。線程2是一個新的線程,用來解釋HTML文檔。緩存
網頁的加載和渲染過程的基本工做方式以下:服務器
HTML支持的資源大體有:Html/Js/CSS/圖片/svg/視頻、音頻等,資源在加載過程當中分爲在緩存中和不在緩存中兩種狀況。網絡
例如在解析Html過程當中,發現一個img標籤,webkit會專門建立一個ImageLoader去加載該資源。因爲獲取資源耗時較長,一般是異步執行的,也就是說資源的獲取和加載不會阻礙當前Webkit的渲染過程,例如圖片/CSS。
固然某些資源例如JS會阻礙主線程的渲染。Webkit會怎麼作呢?當前的主線程被阻礙時,webkit會另起一個線程去遍歷後面的HTML網頁,收集須要的資源URL,發送請求。這樣就能夠避免被阻礙。與此同時,Webkit可以併發下載這些資源,甚至併發下載JS代碼資源,這種機制對於網頁的加速加載非常明顯。
這個地方說法跟一般講的將script標籤加上async屬性或者放在body結束標籤的前面來提高性能的說法不太一致。書中給出的解釋是,就算webkit有本身的優化策略,但仍是建議加上async屬性或者放在body結束標籤的前面,由於並非全部的渲染引擎都做了如此的考慮
緩存資源池是有限的,必須有響應的機制來替換其中的資源,這個機制就是LRU(Last Recent Used)最少使用原則。
網絡請求中,DNS解析和TCP鏈接佔用大量的時間。網頁開發者能夠從如下方面着手減小這一部分時間
<Link rel="dns-prefetch" href="...">
減小資源的數量
在Render進程中有一個線程,該線程用來處理HTML文檔的解釋任務。由於JS代碼可能會修改文檔結構,因此JS代碼的執行會阻塞後面節點的建立,同時也會阻礙後面的資源下載。因此有兩點建議
建議1、
<html> <head> <script type="" async> ... </script> </head> <body> <img src="" /> </body> <html>
建議2、
<html> <head> </head> <body> <img src="" /> <script type=""> ... </script> </body> <html>
但其實在執行JS代碼時,webkit有本身的優化機制,webkit會先暫停JS執行,掃描後面的詞語,若是發現有其它資源,使用預資源加載器來發送請求,在這以後才執行JS代碼。儘管如此,仍是推薦按建議的寫代碼,畢竟不是全部的渲染引擎都作了考慮。
事件分爲3個階段,1事件捕獲階段,2處於目標事件階段,3冒泡階段,可使用event.phase獲取當前所屬的階段。使用addEventListner默認是在冒泡階段捕獲事件,除非最後一個參數制定個爲true;
大多數狀況下,都是將事件處理程序添加到事件流的冒泡階段,能夠最大程度兼容各類瀏覽器。最好只在須要在事件到達目標以前捕獲它時才添加到捕獲階段。
<html> <body id="body"> <div id="div"> <span id="span">span元素</span> </div> <script type="text/javascript"> function onSpan(event) { console.log('on span'); } function onDiv(event) { console.log('on div'); } function onBody(event) { console.log('on body'); } window.onload = function () { const spanEle = document.getElementById('span'); spanEle.addEventListener('click', onSpan); const divEle = document.getElementById('div'); divEle.addEventListener('click', onDiv); const bodyEle = document.getElementById('body'); bodyEle.addEventListener('click', onBody, true); } </script> </body> </html>
點擊span後代碼執行順序爲 body、 span、 div
在chrome的console中使用document查看當前頁面的DOM樹結構。當渲染引擎接收到 CSS 文本時,會執行一個轉換操做,將 CSS 文本轉換爲瀏覽器能夠理解的結構——styleSheets。在控制檯中輸入 document.styleSheets就能夠看到對應的結構。總結以下
由於頁面中有不少複雜的效果,如一些複雜的 3D 變換、頁面滾動、video節點,或者使用 z-indexing 作 z 軸排序等,爲了更加方便地實現這些效果,渲染引擎還須要爲特定的節點生成專用的圖層,並生成一棵對應的圖層樹(LayerTree)。
具體如下狀況會生成單獨的合成層:
每一個RenderLayer對象能夠被想象成圖像中的一個層,各個層一同構成了一個圖像,在渲染過程當中,每一個層對應網頁中的一個或者一些可視元素,這些元素繪製內容到該層上,把這個過程稱爲繪圖操做。若是繪圖操做須要GPU完成,稱之爲GPU硬件加速繪圖。理想狀況下,每一個層都有個繪製的存儲區域,這個存儲區域用來保存繪圖的結果。最後,須要將這些層的內容合併到同一個圖像中,稱之爲合成。
網頁分層有兩個緣由:一是爲了方便網頁開發者開發網頁並設置網頁的層次;二是爲了webkit處理上的遍歷,也就是爲了簡化渲染邏輯。
從輸入網頁URL到構建完DOM樹這個過程:
接下來就是Webkit利用CSS和DOM樹構建RenderObject樹直到繪圖上下文,具體過程以下:
網頁加載後,每當從新繪製新的一幀時,通常須要通過三個階段:計算佈局--繪圖--合成。其中前兩個階段比較耗時間,合成時間相對要少一些。在實際應用中,能夠經過以下方法來減小webkit繪製每一幀所須要的時間:1、使用合適的網頁分層技術以減小須要從新計算的佈局和繪圖;2、使用CSS 3D變形和動畫技術。
JS語言的一個特色是它是無類型語言,沒有辦法在編譯的時候知道變量類型,運行的時候才能肯定。在運行時計算和決定類型,會帶來很嚴重的性能損耗。
這相較於靜態語言例如C++的區別是,靜態語言只須要知道變量的地址及類型,地址加上類型的長度,就能夠得出該變量的值。
JS引擎就是可以將JS代碼處理並執行的運行環境。JS引擎執行過程主要分爲三個階段,分別是語法分析,預編譯和執行階段。
語法分析就是經過詞法分析和語法分析獲得語法樹的過程,若是在構造語法樹的時候,發現錯誤,就會報錯並結束整個代碼塊的解析。
首先了解變量對象(Variable Object, 縮寫爲VO)是用於存儲執行上下文中的:
在函數上下文中,變量對象被表示爲活動對象AO;
function test(a, b) { var c = 10; function d() {} var e = function _e() {}; (function x() {}); b=20; } test(10)
VO按照以下順序填充:
所以
AO(test) = { a: 10, b: undefined, c: undefined, d: <ref to func "d"\> e: undefined };
AO(test) = { a: 10, b: 20, c: 10, d: <reference to FunctionDeclaration "d"\> e: function \_e() {}; };