衣食父母-瀏覽器
我覺得文章題目起的挺現實,在BS大行其道的今天,瀏覽器作為一款window軟體已經是很多程式設計師兄弟的衣食父母,所以瞭解一下瀏覽器是很必要的。
1、背景
作為前端程式設計師一定要好奇從位址列輸入地址後到底發生了什麼
主流瀏覽器
IE、Firefox、Safari、Chrome、Opera五大家族, Firefox、Chrome是開源的完全開源的,safari部分開源
瀏覽器的主要構成
使用者介面、瀏覽器引擎、渲染引擎、網路、js直譯器、UI後端、資料儲存,google為每個tab頁分一個渲染引擎,
(1) 瀏覽器引擎是一個主程序、用來管理渲染引擎所在的程序,渲染引擎對應的程序可能只屬於一個tab頁(chrome),而瀏覽器程序屬於整個瀏覽器
(2) 渲染引擎沒有訪問作業系統的許可權(檔案、網路、裝置)而瀏覽器引擎有,這樣的目的是有惡意網站時不會損害整個瀏覽器或者作業系統
(3) 當用戶在位址列輸入網址請求網頁時,渲染引擎向瀏覽器引擎發出請求:依次呼叫網路獲取資源,請求的資源到達後,瀏覽器引擎把資源傳給渲染
渲染引擎,渲染引擎將獲取的資源進行解析(html css js),有一些元件(佈局程序就屬於其中的某個元件)格式化後傳給瀏覽器引擎,瀏覽器在介面中將介面呈現出來
渲染引擎
渲染引擎有兩種Mozilla和webkit,熟悉css的同學可能感覺這倆外國字挺熟悉,對啊css相容性的屬性都會加這倆字首,渲染引擎就是將請求的資源在瀏覽器中呈現出來
渲染主流程
首先是獲取請求的文件,文件由8kb的資料塊構成,8kb的大小是由tcp預設緩衝區的大小決定的 。構建成dom樹->構建render樹->佈局render樹->繪製render樹。
(1) 渲染引擎從瀏覽器引擎獲取html文件後開始解析,進行詞法分析(將輸入分成可以理解的單詞)和語法分析(對應語言的語義規則,描述文件內容),最終根據文件標籤構建一棵DOM樹(可以理解成c++的一種資料結構),解析過程如果碰到了行內、內聯、外聯的css,對應的子程序著手cssom樹的構建(可以理解成c++的一種資料結構,描述樣式規則),由於是兩個程序所以沒有阻塞的問題,如果解析過程中碰到了javascript,那麼DOM,並且javascript的執行需要等到cssom構建完畢,下一步構建渲染樹是需要兩個樹都是在完成構建的狀態。
(2) 此時要構建渲染樹了,先從DOM樹的根節點開始逐層遍歷,然後依次在cssom中找到對應的樣式併合併到渲染樹,如果碰到了隱藏樣式那麼
直接在渲染樹種忽略。
(3) 對渲染樹進行'佈局',之前的所有操作都沒涉及瀏覽器視窗,他們就是在這個階段聯絡起來的,這樣渲染樹才能適應不同大小的視窗,這時所有的位置和尺寸都被轉換為畫素(px)
(4) 最後是將佈局樹轉換格式傳給瀏覽器引擎,在瀏覽器視窗繪製。
2、css阻塞
從上文中我們知道css是阻塞的也是非阻塞的,阻塞渲染樹的構建,但是對於dom樹的構建是不阻塞的。如果在構建渲染樹時是不阻塞的會發生什麼,我們會看到'純html'沒有任何樣式,這樣是不友好的,但是某些時候我們確實想讓它是不阻塞的,比如涉及列印的樣式,在特定大屏上的樣式,因為他們對渲染的影響比較小,此時可以採用媒體屬性(media)
<link href="style.css" rel="stylesheet"> <link href="print.css" rel="stylesheet" media="print"> <link href="style.css"rel="stylesheet" media="all"> <link href="portrait.css" rel="stylesheet" media="orientation:portrait"> <link href="other.css" rel="stylesheet" media="(min-width: 40em)">
注:不阻塞不是不下載,只是在首次合成渲染樹時不受它的阻塞
3、javascript阻塞
從衣食父母-瀏覽器中我們知道javascript指令碼的執行是會阻塞DOM樹的構建的,並且在cssom構建完畢前停止執行,這樣會有很大的效能開銷,有沒有不阻塞的方法呢?
1、外部js非同步載入
<script src="app.js" async></script>
2、 內聯js非同步執行
function h () { console.log(document.querySelectorAll('h1')) } setTimeout(h, 0)