一、瀏覽器的渲染程序
-

-
注意:這個程序是逐步完成的,為了更好的用戶體驗,渲染引擎將會盡可能早的將內容呈現到螢屏上,并不會等到所有的html 都決議完成之后再去構建和布局 render 樹,它是決議完一部分內容就顯示一部分內容,同時,可能還在通過網路下載其余內容,
-
渲染程序解讀如下:
- 首先決議收到的檔案,根據檔案定義構建一棵 DOM 樹,DOM 樹是由 DOM 元素及屬性節點組成的,
- 然后對 CSS 進行決議,生成 CSSOM 規則樹,
- 根據 DOM 樹和 CSSOM 規則樹構建渲染樹,渲染樹的節點被稱為渲染物件,渲染物件是一個包含有顏色和大小等屬性的矩形,渲染物件和 DOM 元素相對應,但這種對應關系不是一對一的,不可見的 DOM 元素不會被插入渲染樹,還有一些 DOM元素對應幾個可見物件,它們一般是一些具有復雜結構的元素,無法用一個矩形來描述,
- 當渲染物件被創建并添加到樹中,它們并沒有位置和大小,所以當瀏覽器生成渲染樹以后,就會根據渲染樹來進行布局(也可以叫做回流),這一階段瀏覽器要做的事情是要弄清楚各個節點在頁面中的確切位置和大小,通常這一行為也被稱為“自動重排”,
- 布局階段結束后是繪制階段,遍歷渲染樹并呼叫渲染物件的 paint 方法將它們的內容顯示在螢屏上,繪制使用 UI 基礎組件,
二、瀏覽器渲染優化
1.針對JavaScript
- JavaScript既會阻塞HTML的決議,也會阻塞CSS的決議,因此我們可以對JavaScript的加載方式進行改變,來進行優化
- 盡量將JavaScript檔案放在body的最后
<scipt>標簽的引入資源方式有三種,有一種就是我們常用的直接引入,還有兩種就是使用 async 屬性和 defer 屬性來異步引入,兩者都是去異步加載外部的JS檔案,不會阻塞DOM的決議(盡量使用異步加載),三者的區別如下:- script 立即停止頁面渲染去加載資源檔案,當資源加載完畢后立即執行js代碼,js代碼執行完畢后繼續渲染頁面
- async 是在下載完成之后,立即異步加載,加載好后立即執行,多個帶async屬性的標簽,不能保證加載的順序
- defer 是在下載完成之后,立即異步加載,加載好后,如果 DOM 樹還沒構建好,則先等 DOM 樹決議好再執行;如果DOM樹已經準備好,則立即執行,多個帶defer屬性的標簽,按照順序執行
2.針對CSS
- 使用CSS有三種方式:使用link、@import、行內樣式,其中link和@import都是匯入外部樣式,它們之間的區別:
- link:瀏覽器會派發一個新的執行緒(HTTP執行緒)去加載資源檔案,與此同時GUI渲染執行緒會繼續向下渲染代碼
- @import:GUI渲染執行緒會暫時停止渲染,去服務器加載資源檔案,資源檔案沒有回傳之前不會繼續渲染(阻礙瀏覽器渲染)
- style:GUI直接渲染
- 所以,在開發程序中,匯入外部樣式使用link,而不用@import,如果css少,盡可能采用內嵌樣式,直接寫在style標簽中,
- 外部樣式如果長時間沒有加載完畢,瀏覽器為了用戶體驗,會使用瀏覽器會默認樣式,確保首次渲染的速度,所以CSS一般寫在headr中,讓瀏覽器盡快發送請求去獲取css樣式
3.針對DOM樹、CSSOM規則樹
- HTML檔案的代碼層級盡量不要太深
- 使用語意化的標簽,來避免不標準語意化的特殊處理
- 減少CSS代碼的層級,因為選擇器是從右向左進行決議的
4.減少回流與重繪
- 瀏覽器針對頁面的回流與重繪,進行了自身的優化——渲染佇列,瀏覽器會將所有的回流、重繪的操作放在一個佇列中,當佇列中的操作到了一定的數量或者到了一定的時間間隔,瀏覽器就會對佇列進行批量處理,這樣就會讓多次的回流、重繪變成一次回流重繪,
- CSS:
- 避免設定多層行內樣式
- 如果需要設定影片效果,最好使用absolute或者fixed,使元素脫離檔案流,這樣他們發生變化就不會影響其他元素
- 避免使用CSS運算式(例如:calc())
- JS:
- 避免頻繁操作樣式,最好將樣式串列定義為class并一次性更改class屬性
- 避免頻繁操作DOM,創建一個documentFragment,在它上面應用所有DOM操作,最后再把它添加到檔案中
- 可以先為元素設定為不可見:display: none,操作結束后再把它顯示出來,因為在display屬性為none的元素上進行的DOM操作不會引發回流和重繪
三、渲染程序中遇到 JS 檔案如何處理
- JavaScript 的加載、決議與執行會阻塞檔案的決議,也就是說,在構建 DOM 時,HTML 決議器若遇到了 JavaScript,那么它會暫停檔案的決議,將控制權移交給 JavaScript 引擎,等 JavaScript 引擎運行完畢,瀏覽器再從中斷的地方恢復繼續決議檔案,也就是說,如果想要首屏渲染的越快,就越不應該在首屏就加載 JS 檔案,這也是都建議將 script 標簽放在 body 標簽底部的原因,當然在當下,并不是說 script 標簽必須放在底部,因為你可以給 script 標簽添加 defer 或者 async 屬性,
四、檔案的預決議
- Webkit 和 Firefox 都做了這個優化,當執行 JavaScript 腳本時,另一個執行緒決議剩下的檔案,并加載后面需要通過網路加載的資源,這種方式可以使資源并行加載從而使整體速度更快,需要注意的是,預決議并不改變 DOM 樹,它將這個作業留給主決議程序,自己只決議外部資源的參考,比如外部腳本、樣式表及圖片,
五、CSS 如何阻塞檔案決議
- 理論上,既然樣式表不改變 DOM 樹,也就沒有必要停下檔案的決議等待它們,然而,存在一個問題,JavaScript 腳本執行時可能在檔案的決議程序中請求樣式資訊,如果樣式還沒有加載和決議,腳本將得到錯誤的值,顯然這將會導致很多問題,所以如果瀏覽器尚未完成 CSSOM 的下載和構建,而我們卻想在此時運行腳本,那么瀏覽器將延遲 JavaScript 腳本執行和檔案的決議,直至其完成 CSSOM 的下載和構建,也就是說,在這種情況下,瀏覽器會先下載和構建 CSSOM,然后再執行 JavaScript,最后再繼續檔案的決議,
六、優化關鍵渲染路徑
- 優化方法如下:
- 對關鍵路徑進行分析和特性描述:資源數、位元組數、長度
- 最大限度減少關鍵資源的數量:洗掉它們,延遲它們的下載,將它們標記為異步等
- 優化關鍵位元組數以縮短下載時間(往返次數)
- 優化其余關鍵資源的加載順序:您需要盡早下載所有關鍵資產,以縮短關鍵路徑長度
七、阻塞渲染的情況
- 首先渲染的前提是生成渲染樹,所以 HTML 和 CSS 肯定會阻塞渲染,如果你想渲染的越快,你越應該降低一開始需要渲染的檔案大小,并且扁平層級,優化選擇器,然后當瀏覽器在決議到 script 標簽時,會暫停構建 DOM,完成后才會從暫停的地方重新開始,也就是說,如果你想首屏渲染的越快,就越不應該在首屏就加載 JS 檔案,這也是都建議將 script 標簽放在 body 標簽底部的原因,當然在當下,并不是說 script 標簽必須放在底部,因為你可以給 script 標簽添加 defer 或者 async 屬性,當 script 標簽加上 defer 屬性以后,表示該 JS 檔案會并行下載,但是會放到 HTML 決議完成后順序執行,所以對于這種情況你可以把 script 標簽放在任意位置,對于沒有任何依賴的 JS 檔案可以加上 async 屬性,表示 JS 檔案下載和決議不會阻塞渲染,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/523209.html
標籤:其他
