??瀏覽器原理 之 頁面形成的原理和性能優(yōu)化篇
時間:2023-07-03 05:12:02 | 來源:網(wǎng)站運營
時間:2023-07-03 05:12:02 來源:網(wǎng)站運營
??瀏覽器原理 之 頁面形成的原理和性能優(yōu)化篇:
(不想在本站重新排版,太麻煩了)
原本地址:
github地址:
> __大家好,我是林一一,這是一篇關(guān)于瀏覽器是如何渲染一個頁面形成的原理,話不多說,直接開始閱讀吧 __
## 001 瀏覽器的底層渲染頁面篇
> 瀏覽器中的5個進程

> 瀏覽器在獲取服務(wù)器的資源后將 html 解析成 DOM 樹,CSS 計算成 CSSOM 樹,將兩者合成 render tree。具體如下瀏覽器根據(jù) render tree 布局生成一個頁面。**需要理解的是瀏覽器從服務(wù)器獲取回來的資源是一個個的字節(jié)碼`3C 6F 6E 62 ....`等,瀏覽器會按照一套規(guī)范`W3C`將字節(jié)碼最后解析一個個的代碼字符串才成為我們看到的代碼**。
### 瀏覽器加載資源的機制
* 瀏覽器會開辟一個 GUI 渲染線程,自上而下執(zhí)行代碼,專門用于渲染渲染頁面的線程。
### 遇到 CSS 資源
* 遇到 `<style>` 內(nèi)聯(lián)標簽會交給 GUI 渲染線程解析,但是遇到 `<link>` 標簽會異步處理,瀏覽器會開辟一個 `HTTP` 請求處理的線程,GUI 渲染線程繼續(xù)往下執(zhí)行
* 如果遇到`@import` 時,也會開辟一個新的 `HTTP` 請求線程處理,由于 `@import` 是同步的 GUI 渲染線程會阻塞等待請求的結(jié)果。
> 需要注意 chrome 中,同一個源下,最多同時開辟 6-7 和 HTTP 請求線程。
### 遇到 JS 資源

> 最底部的線表示 GUI 線程的過程,渲染線程遇到不同情況下的script資源,有不同的處理。
* 遇到 `<script></script>` 資源,默認是同步的。 此時 GUI 渲染線程會阻塞。等待 JS 渲染線程渲染結(jié)束后,GUI 線程才會繼續(xù)渲染。
* 如果遇到 `<script async></script>` 那么資源是異步的 `async`,瀏覽器也會開辟一個 `HTTP` 請求線程加載資源,這時 GUI 渲染線程會繼續(xù)向下渲染,請求的資源回來后 JS 渲染線程開始執(zhí)行,GUI 線程再次被阻塞。
* 如果遇到 `<script defer></script>` 和 async 類似都會開辟一個新的`HTTP`線程,GUI 繼續(xù)渲染。和 async 不一樣的地方在于,`defer` 請求回來的資源需要等待 GUI 同步的代碼執(zhí)行結(jié)束后才執(zhí)行 defer 請求回來的代碼。
> async 不存在資源的依賴關(guān)系先請求回來的先執(zhí)行。defer 需要等待所有的資源請求回來以后,按照導入的順序/依賴關(guān)系依次執(zhí)行。
### 圖片或音頻
* 遇到 `<img/>` 異步,也會開辟一個新的 HTTP 線程請求資源。GUI 繼續(xù)渲染,當 GUI 渲染結(jié)束后,才會處理請求的資源。
__需要注意的是:假設(shè)某些資源加載很慢,瀏覽器會忽略這些資源接著渲染后面的代碼,在chrome瀏覽器中會先使用預加載器html-repload-scanner先掃描節(jié)點中的 src,link等先進行預加載,避免了資源加載的時間__
### 瀏覽解析資源的機制
* 瀏覽器是怎樣解析加載回來的資源文件的? 頁面自上而下渲染時會確定一個 `DOM樹`,`CSSOM樹`,最后 `DOM樹` 和 `CSSOM樹` 會被合并成 `render 樹`,這些所謂的樹其實都是js對象,用js對象來表示節(jié)點,樣式,節(jié)點和樣式之間的關(guān)系。
### DOM 樹
> 所謂的 DOM 樹是確定好節(jié)點之間的父子、兄弟關(guān)系。這是 GUI 渲染線程自上而下渲染結(jié)束后生成的,等到 CSS 資源請求回來以后會生成 CSSOM 樣式樹。

### CSSOM 樹
> CSSOM(CSS Object Model), CSS 資源加載回來以后會被 GUI 渲染成 `樣式樹`

### Render tree 渲染樹
> 瀏覽器根據(jù) Render tree 渲染頁面需要經(jīng)歷下面幾個步驟。注意 `display:node` 的節(jié)點不會被渲染到 render tree 中

* layout 布局,根據(jù)渲染樹 `計算出節(jié)點在設(shè)備中的位置和大小`。
* 分層處理。按照層級定位分層處理
* painting 繪制頁面

> 上面的圖形就是瀏覽器分成處理后的顯示效果
## 002 瀏覽器的性能優(yōu)化篇
> 前端瀏覽器的性能優(yōu)化,可以從CRP: 關(guān)鍵渲染路徑入手
### DOM Tree
* 減少 DOM 的層級嵌套
* 不要使用被標準標簽
### CSSOM
* 盡量不要使用 `@import`,會阻礙`GUI`渲染線程。
* CSS 代碼量少可以使用內(nèi)嵌式的`style`標簽,減少請求。
* 減少使用`link`,可以減少 HTTP 的請求數(shù)量。
* CSS 選擇器鏈盡可能短,因為CSS選擇器的渲染時從右到左的。
* 將寫入的 link 請求放入到`<head></head>` 內(nèi)部,一開始就可以請求資源,GUI同時渲染。
### 其他資源
* `<script></script>` 中的同步 js 資源盡可能的放入到頁面的末尾,防止阻礙`GUI`的渲染。如果遇到 `<script async/defer></script>` 的異步資源,GUI 渲染不會中斷,但是JS資源請求回來以后會中斷 GUI 的渲染。
* `<img />` 資源使用懶加載,懶加載:第一次加載頁面時不要加載圖片,因為圖片也會占據(jù) HTTP 的數(shù)量。還可以使用圖片 base64,代表圖片。
## 003 回流和重繪篇
> layout 階段就是頁面的回流期,painting 就是重繪階段。第一次加載頁面時必有一次回流和重繪。
* 瀏覽器渲染頁面的流程
> 瀏覽器會先把 `HTML` 解析成 `DOM樹` 計算 `DOM` 結(jié)構(gòu);然后加載 `CSS` 解析成 `CSSOM`;最后將 `DOM 和 CSSOM` 合并生成渲染樹 `Render Tree`,瀏覽器根據(jù)頁面計算 layout(重排階段);最后瀏覽器按照 `render tree` 繪制(painting,重繪階段)頁面。
### 重排(DOM 回流)
> 重排是指 `render tree` 某些 `DOM` 大小和位置發(fā)生了變化(頁面的布局和幾何信息發(fā)生了變化),瀏覽器重新渲染 `DOM` 的這個過程就是`重排(DOM 回流)`,重排會消耗頁面很大的性能,這也是虛擬 DOM 被引入的原因。
#### 發(fā)生重排的情況
* 第一次頁面計算 layout 的階段
* 添加或刪除DOM節(jié)點,改變了 `render tree`
* 元素的位置,元素的字體大小等也會導致 DOM 的回流
* 節(jié)點的幾何屬性改變,比如`width, height, border, padding,margin等`被改變
* 查找盒子屬性的 `offsetWidth、offsetHeight、client、scroll`等,瀏覽器為了得到這些屬性會重排操作。
* 框架中 `v-if` 操作也會導致回流的發(fā)生。
* 等等
#### 一道小題,問下面的代碼瀏覽器重排了幾次(chrome新版瀏覽器為主)?
``` js
box.style.width = "100px";
box.style.width = "100px";
box.style.position = "relative";
```
> 你可能會覺得是3次,但是在當代瀏覽器中,瀏覽器會為上面的樣式代碼開辟一個渲染隊列,將所有的渲染代碼放入到隊列里面,最后一次更新,所以重排的次數(shù)是1次。 問下面的代碼會導致幾次重排
``` js
box.style.width = "100px";
box.style.width = "100px";
box.offsetWidth;
box.style.position = "relative";
```
> 答案是2次,因為 `offsetWidth` 會導致渲染隊列的刷新,才可以獲取準確的 `offsetWidth` 值。最后 `position` 導致元素的位子發(fā)生改變也會觸發(fā)一次回流。所以總共有2次。
### 重繪
> 重繪是指 頁面的樣式發(fā)生了改變但是 `DOM` 結(jié)構(gòu)/布局沒有發(fā)生改變。比如顏色發(fā)生了變化,瀏覽器就會對需要的顏色進行重新繪制。
#### 發(fā)生重繪的情況
* 第一次頁面 painting 繪制的階段
* 元素顏色的 `color` 發(fā)生改變
### 直接合成
> 如果我們更改了一個不影響布局和繪制的屬性,瀏覽器的渲染引擎會跳過重排和重繪的階段,直接合成
* 比如我們使用了CSS 的 transform 屬性,瀏覽器的可以師姐合成動畫效果。
__重排一定會引發(fā)重繪,但是重繪不一定會導致重排__
#### 重排 (DOM回流)和重繪嗎?說一下區(qū)別
> 思路:先講述瀏覽器的渲染機制->重排和重繪的概念->怎么減少重排和重繪。。。
#### 區(qū)別
> 重排會導致 `DOM結(jié)構(gòu)` 發(fā)生改變,瀏覽器需要重新渲染布局生成頁面,但是重繪不會引發(fā) DOM 的改變只是樣式上的改變,前者的會消耗很大的性能。
#### 如何減少重排和重繪
* 1. 避免使用 `table` 布局,因為 `table` 布局計算的時間比較長耗性能;
* 2. 樣式集中改變,避免頻繁使用 style,而是采用修改 class 的方式。
* 3. 避免頻繁操作 DOM,使用vue/react。
* 4. 樣式的分離讀寫。設(shè)置樣式`style`和讀取樣式的`offset`等分離開,也可以減少回流次數(shù)。
* 5. 將動畫效果設(shè)計在文檔流之上即 `position` 屬性的 `absolute` 或 `fixed` 上。使用 GPU 加速合成。
## 參考
《瀏覽器工作原理與實踐》
[Render Tree頁面渲染](探網(wǎng)絡(luò)系列(1)-TCP三次握手&Render Tree頁面渲染=>從輸入URL到頁面顯示的過程?)
## 結(jié)束
>__感謝閱讀到這里,如果這篇文章能對你有點啟示或幫助歡迎給 ,我是林一一,下次見。__
**瀏覽器原理篇:[本地存儲和瀏覽器緩存](瀏覽器原理-瀏覽器緩存和本地存儲篇)**
**Vue 原理篇:[Vue高頻原理詳細解答](Vue 高頻原理面試篇+詳細解答)**
**webpack原理篇: [編寫loader和plugin](編寫 loader 和 plugins)**
[github文章合集](lurenacm/againJS)