想著優(yōu)化瀏覽器打開網(wǎng)頁的體驗师幕,那么這周粟按,首先了解一下瀏覽器的工作原理吧。談到瀏覽器的原理分析霹粥,網(wǎng)上自然有一大堆技術(shù)文章灭将,個人覺得以色列開發(fā)人員塔利·加希爾的研究成果也是夠的了,足夠自己學(xué)習(xí)了蒙挑。
如果你打開了宗侦,會發(fā)現(xiàn)文章很長,更多是從研究的角度去分析忆蚀。下面將更多的從iOS 開發(fā)者的角度矾利,把關(guān)心的問題提出來,希望大家能一起探討馋袜。
頁面展示timeline
重點看一下男旗,瀏覽器加載和渲染界面這個過程。首先瀏覽器由7個部分組成:
- User Interface
定義了一些常用的瀏覽器插件- Browser engine
平臺應(yīng)用的相關(guān)借口欣鳖,在用戶界面和呈現(xiàn)引擎之間傳送指令- Rendering engine
處理HTML 和 CSS 的解析與渲染- Networking
處理網(wǎng)絡(luò)請求- JavaScript Interpreter
解析和執(zhí)行JS 代碼- UI Backend
繪制基礎(chǔ)元件察皇,如組合框與窗口。它提供平臺無關(guān)的接口泽台,內(nèi)部使用操作系統(tǒng)的相應(yīng)實現(xiàn)- Data Persistence
持久層什荣。瀏覽器需要把所有數(shù)據(jù)存到硬盤上,如cookies怀酷,圖片稻爬,css等。新的HTML規(guī)范 (HTML5) 規(guī)定了一個完整(雖然輕量級)的瀏覽器中的數(shù)據(jù)庫:’web database’
瀏覽器渲染過程
- 解析html 為DOM 樹
- 渲染樹結(jié)構(gòu)
- 布局渲染樹
- 繪制渲染樹
解析html 為DOM 樹 :
1)HTML字節(jié)流解碼變?yōu)樽址魍梢馈8鶕?jù)不同編碼方式桅锄,如UTF-8 GBK來解碼
2)詞法分析:將字符流解析為一個個詞語
3)語法分析:通過不同標(biāo)簽琉雳,生成node節(jié)點
4)構(gòu)建DOM樹:將node節(jié)點組織成DOM樹
<html>
<body>
<p>Hello World</p>
<div>![](example.png)</div>
</body>
</html>
CSS解析器讀取CSS文件,得到元素最匹配的樣式
1)經(jīng)過詞法分析和語法分析友瘤,生成一個個CSS規(guī)則翠肘。規(guī)則由選擇器和一個key:value對組成的屬性集合構(gòu)成
2)進行規(guī)則匹配:根據(jù)元素信息,如id class 標(biāo)簽辫秧,通過不同優(yōu)先級得到元素最匹配的CSS規(guī)則
p,div {
margin-top: 3px;
}
.error {
color: red;
}
渲染樹結(jié)構(gòu):
生成RenderObject樹:由DOM樹構(gòu)建RenderObject樹束倍,并將CSS得到的元素匹配的樣式存入到RenderObject中。
布局渲染樹 : 根據(jù)RenderObject中的樣式屬性茶没,先測量元素的寬高肌幽,這個過程一般需要遞歸晚碾,因為父元素的大小會受到子元素影響抓半。然后計算根據(jù)框模型,由paddind border margin計算布局格嘁。
繪制渲染樹 : 先繪制元素背景笛求,然后是浮動部分,最后是前景(content糕簿,padding探入,border等部分)。最后得到了用戶可見區(qū)域(ViewPort)的內(nèi)存表示懂诗。
通常頁面的加載速度會受HTML蜂嗽,CSS ,JS 的影響殃恒,那么三者又是怎么加載的植旧?
HTML ,CSS, JavaScript 加載順序
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<link rel="stylesheet" href="./style1.css">
</head>
<body>
<P>Hello Alibaba!</P>
<section> Hello Alibaba!</section>
![](./Alibaba.jpg)
<script src="./main1.js"></script>
</body>
</html>
上述代碼是最普通也是最簡單的一個HTML模板頁面,也遵循了樣式表置于head离唐、腳本置于與底端這些基本準(zhǔn)則病附,下面我們來分析一下瀏覽器如何按時間一步一步的加載出這個頁面:
1. 瀏覽器接收到HTML模板文件,開始從上到下依次解析HTML亥鬓;
2. 遇到樣式表文件style1.css完沪,這時候瀏覽器停止解析HTML,接著去請求CSS文件嵌戈;
3. 服務(wù)端返回CSS文件覆积,瀏覽器開始解析CSS;
4. 瀏覽器解析完CSS熟呛,繼續(xù)往下解析HTML宽档,碰到DOM節(jié)點,解析DOM惰拱;
5. 瀏覽器發(fā)現(xiàn)img雌贱,向服務(wù)器發(fā)出請求啊送。此時瀏覽器不會等到圖片下載完,而是繼續(xù)渲染后面的代碼欣孤;
6. 服務(wù)器返回圖片文件馋没,由于圖片占用了一定面積,影響了頁面排布降传,因此瀏覽器需要回過頭來重新渲染這部分代碼篷朵;
7. 碰到腳本文件,這時停止所有加載和解析婆排,去請求腳本文件声旺,并執(zhí)行腳本;
8. 加載完所有的HTML段只、CSS腮猖、JS后,頁面就出現(xiàn)在屏幕上了赞枕。
瀏覽器在解析HTML頁面澈缺,是從上到下依次執(zhí)行的,如果在head中引用了js 文件炕婶,而這個文件很大姐赡,js 為阻塞式加載,那么瀏覽器會停止渲染頁面柠掂,等js 文件加載完之后才會繼續(xù)渲染项滑。這就會導(dǎo)致白屏問題,CSS 文件也一樣涯贞,因為CSS文件隊DOM的樣式枪狂,布局有影響,所以瀏覽器會等CSS文件下載完肩狂。
為了避免白屏問題摘完,如果頁面的初始渲染不依賴CSS 和 JS,建議把外部引用的文件寫在最后傻谁。那么問題又來了孝治,如果CSS 文件組后加載的話,會出現(xiàn)短暫無樣式的頁面审磁。
因為JS為阻塞式的加載谈飒,加載過程按照文檔順序從上到下,因此有依賴關(guān)系的JS 要按順序放好态蒂,并且把不必要的JS 放在底部加載杭措。
如何避免白屏和無樣式的頁面問題:
- 帶有defer屬性 的script 標(biāo)簽
<script defer src="script.js"></script>- 帶有async屬性 的script 標(biāo)簽
<script async src="script.js"></script>
即使把外部腳本寫在前面也不怕了,瀏覽器會繼續(xù)向下解析HTML網(wǎng)頁钾恢,解析完就渲染到頁面上手素,同時并行下載script標(biāo)簽中的外部腳本鸳址。defer 和async 的區(qū)別在于,前者會保證外部腳本的執(zhí)行順序泉懦,async 無法保證腳本的執(zhí)行順序稿黍。哪個腳本先下載結(jié)束,就先執(zhí)行那個腳本崩哩。
參考資料:
瀏覽器的工作原理:新式網(wǎng)絡(luò)瀏覽器幕后揭秘
白屏問題與FOUC無樣式內(nèi)容閃爍/加載異步