web前端項目性能優化

web前端項目性能優化

本篇文章主要回答兩個問題:

  1. 什麼是迴流(reflow)、重繪(repaint)?它們將怎樣影響前端性能?
  2. 一些前端頁面卡頓的原因以及解決方法

1. 什麼是迴流(reflow)、重繪(repaint)?

參考的文章:https://www.html.cn/archives/4996

https://blog.csdn.net/claireke/article/details/51375622

è¿éåå¾çæè¿°

首先了解瀏覽器頁面渲染順序:

1. HTML文檔和 CSS文件同時開始渲染、HTML文檔生成DOM樹、CSS文件生成CSSOM對象

2. CSSOM對象和DOM樹做連接匹配生成render樹

3. render樹在頁面上進行佈局,這個過程叫reflow

4. render樹在頁面上進行繪製,這個過程叫repaint

概念解釋:

reflow: 當render樹中的一部分或者全部因爲大小邊距等問題發生改變而需要重建的過程叫做迴流 ( 幾何大小和位置發生改變 )
repaint: 當元素的一部分屬性發生變化,如外觀背景色不會引起佈局變化而需要重新渲染的過程叫做重繪 ( 文字、邊框、背景顏色、外觀風格 )

注意:迴流必定觸發重繪,而重繪不一定觸發迴流

引起迴流的原因:

    1.首當其衝自然是dom樹結構變化,比如你刪除或者添加某個node.
    2.元素幾何屬性變化,包括margin,padding,height,width,border等
    3.瀏覽器窗口發生變化 resize 事件發生時
    4.激活僞類 hover
    5.計算offsetWidth和offsetHeight屬性值的時候

現在我們大概都能得出的結論是:迴流比重繪的代價要高(因爲迴流需要頁面的節點進行重新構建排列,並且還要再次進行重繪),至於具體的花銷跟render樹有多少節點需要重新構建有關。

2. 如何減少迴流(reflow)、重繪(repaint)?

1.使用display:none技術,只引發兩次迴流和重繪。

原理:由於display屬性爲none的元素不在渲染樹中,對隱藏的元素操 作不會引發其他元素的重排。如果要對一個元素進行復雜的操作時,可以先隱藏它,操作完成後再顯示。這樣只在隱藏和顯示時觸發2次重排。

2.使用DocumentFragment進行緩存操作,引發一次迴流和重繪。

原理:我們經常使用javascript來操作DOM元素,比如使用appendChild()方法。每次調用該方法時,瀏覽器都會重新渲染頁面。如果大量的更新DOM節點,則會非常消耗性能,影響用戶體驗

  javascript提供了一個文檔片段DocumentFragment的機制。如果將文檔中的節點添加到文檔片段中,就會從文檔樹中移除該節點。把所有要構造的節點都放在文檔片段中執行,這樣可以不影響文檔樹,也就不會造成頁面渲染。當節點都構造完成後,再將文檔片段對象添加到頁面中,這時所有的節點都會一次性渲染出來,這樣就能減少瀏覽器負擔,提高頁面渲染速度

 3.不要經常訪問會引起瀏覽器flush隊列的屬性,如果你確實要訪問,利用緩存。利用變量把節點的offsetTop等屬性值緩存起來使用。

原理:如果每句JS操作都去迴流重繪的話,瀏覽器可能就會受不了。所以很多瀏覽器都會優化這些操作,瀏覽器會維護1個隊列,把所有會引起迴流、重繪的操作放入這個隊列,等隊列中的操作到了一定的數量或者到了一定的時間間隔,瀏覽器就會flush隊列,進行一個批處理。這樣就會讓多次的迴流、重繪變成一次迴流重繪。

雖然有了瀏覽器的優化,但有時候我們寫的一些代碼可能會強制瀏覽器提前flush隊列,這樣瀏覽器的優化可能就起不到作用了。當你請求向瀏覽器請求一些 style信息的時候,就會讓瀏覽器flush隊列,比如:

  1. offsetTop, offsetLeft, offsetWidth, offsetHeight
  2. scrollTop/Left/Width/Height
  3. clientTop/Left/Width/Height
  4. width,height
  5. 請求了getComputedStyle(), 或者 IE的 currentStyle

當你請求上面的一些屬性的時候,瀏覽器爲了給你最精確的值,需要flush隊列,因爲隊列中可能會有影響到這些值的操作。即使你獲取元素的佈局和樣式信息跟最近發生或改變的佈局信息無關,瀏覽器都會強行刷新渲染隊列。

3. JS和CSS阻塞導致頁面加載緩慢

參考文章:https://www.jb51.net/css/572702.html

CSS不會阻塞DOM樹解析,但是會阻塞DOM樹渲染(內存中加載好DOM樹,但是頁面會等CSS解析後和DOM輸一起渲染出來)。

CSS加載會阻塞後面的JS語句的執行。

網頁中的資源下載一般是並行的(JS除外),CSS也是,但是某些情況下會出現CSS阻塞資源下載的情況。

因爲js是單線程的,以及html是按順序解析的,瀏覽器加載資源默認按照 html、css、js的順序,爲了避免js對頁面進行DOM操作導致迴流,所以js會阻塞所有資源的下載,css資源加載若在js之前,css會阻塞js下載,因爲css阻塞js,js阻塞所有,變相css阻塞所有。   

可總結如下:    

(1)頁面要等待所有的css加載完成後纔會開始渲染,css的加載不會阻塞DOM樹的加載,但是會阻塞DOM樹的渲染,但css本身是可以並行下載的(會遲遲看不到內容,但是DOM樹已經解析完成)
(2)css加載會阻塞 js 代碼的執行,瀏覽器會維持 html css js 加載順序(內嵌,在css標籤前的內嵌代碼會先執行,在css標籤後的代碼會等待css文件加載完才執行)
(3)嵌入JS會阻塞所有內容的呈現(DOM樹的解析和渲染),而外部JS只會阻塞其後內容的顯示。瀏覽器爲了防止出現JS修改DOM樹,需要重構DOM樹的情況,就會阻止其他資源的下載和呈現。

爲了能讓其他資源先加載(以最快的速度加載),就要避免js文件加載時的阻塞作用。

解決方法:
(1)把css放頭部,把外部js放底部
(2)給script標籤添加defer屬性,僅限外部腳本,defer屬性表示延遲腳本的執行,等到整個文檔解析完再執行,defer屬性能延遲執行,但是不會延遲下載,瀏覽器遇到script就立即下載腳本
(3)在頁面加載完後動態創建腳本元素
(4)執行時間較長過程的函數可以放入settimeout函數中

 4. 服務器文件加載緩慢可開啓GZIP(文件壓縮傳輸)

在服務端配置中開啓GZIP壓縮,它會把瀏覽器請求的頁面,以及頁面中引用的靜態資源以壓縮包的形式發送到客戶端,然後在客戶端完成解壓和拼裝。js文件可以開啓GZIP,但是圖片文件不要,圖片啓用GZip壓縮,不僅浪費了CPU(壓縮需要cpu運算),還增大了體積(壓縮後體積不僅沒有減少,還增大,可參考其他文章實驗分析),勢必影響服務器性能,影響網站速度。

 5. 開啓CDN 

什麼是CDN?

        CDN(Content Delivery Network) 內容分發網絡,CDN的本質仍然是一個緩存,而且將數據緩存在裏用戶最近的地方,使用戶以最快的速度獲取數據,即網絡訪問第一跳。
        由於CDN是部署在網絡運營商的機房,這些運營商又是終端用戶網絡的提供商,因此用戶請求的第一跳就到達CDN服務器,當CDN服務器中緩存有用戶請求的數據時,就可以從CDN直接返回給客戶端瀏覽器,最短路徑的返回響應,加快用戶的訪問速度,減少數據中心的負載壓力。

概況:設置多個節點服務器,分佈在不同區域中,便於用戶進行數據傳遞和訪問。當某一個節點出現問題時,通過其他節點仍然可以完成數據傳輸工作,可以提高用戶訪問網站的響應速度。CDN可以通過不同的域名來加載文件,從而使下載文件的併發連接數大大增加。

      CDN能夠緩存一般的CSS,js圖片等靜態資源文件,而且這些文件的訪問頻率很高,將其緩存在CDN可以極大的提高網站的訪問速度。

6. 資源合併和壓縮減少HTTP請求次數

多次HTTP請求和連接也很消耗時間。

1、js腳本合併(js文件webpack合併打包)
2、css sprite 精靈圖(多個小圖合併)
3、圖片懶加載(不在頁面顯示區域的圖片先不加載)

7. 合理使用HTTP緩存

合理使用HTTP的緩存機制,讓瀏覽器把數據緩存到本地,再次加載同樣的數據的時候,無需再向服務器請求文件,直接可以從本地緩存中讀取,減少讀取時間。

HTTP請求中合理添加 Expires 或 cache-control 報文頭

8. 使用SPDY/HTTP2協議

SPDY,一種開放的網絡傳輸協議,由Google開發,用來發送網頁內容。基於傳輸控制協議(TCP)的應用層協議 ,是 HTTP/2 的前身。SPDY 的作用就是,在不增加域名的情況下,解除最大連接數的限制。主要的特點就是多路複用,他的目的就是致力於取消併發連接上限,減少HTTP連接的次數。

9. 域名發散和域名收斂

9.1 域名發散

        瀏覽器的並行連接數(同域名),在一些現代瀏覽器內每個 hostname 的最大連接數基本都是6個。所以 PC 時代對靜態資源優化時,通常將靜態資源分佈在幾個不同域,保證資源最完美地分域名存儲,以提供最大並行度,讓客戶端加載靜態資源更爲迅速。

        域名發散就是爲了突破瀏覽器對於同一域名併發請求數的限制,使用域名發散爲同一個服務申請多個域名,從而可以一定程度上提高併發量;當然,由於建立新的請求需要一定的代價,因此需要在域名發散與域名收斂間進行trade off,通常發散的域名個數爲2-4個。

9.2 域名收斂

        域名收斂就是將靜態資源放在一個域名下不進行發散,這主要是爲了適應移動端的發展需求;通常DNS是一個開銷較大的操作,而移動端由於網絡帶寬和實時性、資源等的限制,這些開銷對移動端的用戶體驗是致命的,因此需要進行域名收斂。域名收斂,減少域名數量可以降低 DNS 解析的成本。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章