本文提供一個優化網頁性能的大概思路,具體操作網上資料很多。
緩存優化
性能優化第一步,便是管理好頁面的緩存,避免重複下載資源。否則,即增加服務器壓力,又折磨用戶的錢包。
瀏覽器緩存機制
訪問頁面,請求各種資源,瀏覽器檢查本地是否有緩存。
如果有,檢查資源是否過期。沒過期,直接使用緩存。過期了,便向服務器發出請求。
發出的請求中會帶上etag和last-modified首部字段。
服務器會通過Etag和last-modified來判斷瀏覽器緩存的資源是否已經不可用。
如果資源仍然有效,便返回304告知瀏覽器使用緩存。否則返回更新後的資源。
按照這一套邏輯,便可規劃好網站的緩存。
如果資源提前過期,如何通知瀏覽器更新資源?
通常無法做到這一點,因爲瀏覽器發現資源沒過期,根本不會發出請求。 但是可以通過修改資源的網址來實現。所以需要給資源文件名加上版本號或者隨機標記。例如 style.1234.css。 也就是說,不要讓瀏覽器緩存html文件,否則,過期之前,瀏覽器都不會請求服務器。
加載時優化
消滅不必要的下載
最好的優化,便是根本不下載資源。所以要儘量減少比不要的資源。
評估所有依賴是否必要,權衡利弊。
依賴的下載路徑是否可靠,不可用時候是否會阻礙整個頁面。
產品設計時候就需要拋棄浪費帶寬的設計。
壓縮所有可以壓縮的資源
代碼自不用說,都是文本,全部壓縮。
優化圖片
去掉不必要的圖片
多使用css3來代替圖片
使用壓縮率更高的圖片。特別是gif動圖,一些視頻格式(H.264或WebM)的體積比gif小很多。
用藝術字字體,不要用圖片
仔細權衡圖片和文字的關係。要表達一個意思,可能一圖勝千言。多了一張圖片,反而節省了大量文字。
使用progressive jpeg。相比隨着數據下載從上到下顯示的baseline jpeg,progressive jpeg是由模糊到清晰,用戶體驗好,也不會導致reflow。
圖片分辨率要儘可能小,避免圖片分辨率大於顯示分辨率。
爲使用更新瀏覽器的用戶提供更現代的圖片格式。
多種分辨率的位圖供不同頁面大小使用。
要給標籤指明寬高,否則會導致reflow。
使用HTTP/2。比如,精靈圖是由很多小圖片組成的一張大圖片,可以減少http請求。但是卻難以緩存,修改一個小圖片,導致所有小圖片緩存失效。HTTP/2,一個鏈接內可以發起多個請求,便無需使用精靈圖。
優化字體
@font-face 中unicode-range可以制定字符範圍,用來避免下載不需要的語言的字符。
確保字體都被壓縮過。
用@font-face的display屬性和FontFace對象管理好字體加載時的邏輯。
關鍵渲染路徑
瀏覽器渲染一張網頁通過以下步驟。
處理 HTML 標記並構建 DOM 樹。
處理 CSS 標記並構建 CSSOM 樹。
將 DOM 與 CSSOM 合併成一個渲染樹。
根據渲染樹來佈局,以計算每個節點的幾何信息。
將各個節點繪製到屏幕上。
優化關鍵渲染路徑,便是指優化這個渲染過程,讓網頁儘快呈現出來。
css
CSS文件會阻塞渲染。瀏覽器構建好DOM樹後,必須等待CSSOM樹構建完成。
在文檔頂部防止外聯CSS的標籤,讓瀏覽器儘快請求CSS文件。
避免在css文件中使用@import,因爲只有包含import的文件被下載編譯後,瀏覽器纔會發現並下載import的css。
可以考慮使用內聯CSS,無需額外請求,不會阻塞渲染。
js
在CSSOM構建完成前,js不會開始執行。
js也會阻止DOM樹構建。除非在
<script>
標籤上標記async。用Chrome開發者工具的audits檢查網頁。
動畫優化
重繪過程
CSS選擇器
選擇器越複雜,瀏覽器計算得越久。最糟情況下,瀏覽器需要遍歷整個DOM-tree,計算量等於元素總個數乘以選擇器個數。
儘量不要使選擇器太複雜,事先給需要被操作的元素加上類名。
reflow, layout
Chrome, Opera, Safari, Internet Explorer中叫layout. 火狐稱之爲Reflow。
reflow, repaint次數越少越好,牽連的元素越少越好。
reflow總是牽涉整個文檔流。
修改元素css後立刻讀取css計算值,將導致瀏覽器同步reflow,阻塞js線程。
Paint
瀏覽器渲染網頁時,會將網頁分層(layer),最後將不同層合併,然後完成渲染。 同一層中,哪怕只有一個小小的元素髮生變化,整個層都會被repaint。 這一點可以在開發者工具的Paint Profiler界面中觀察到,layer界面中可以觀察網頁有多少個layer。
paint是耗費性能的。
修改transform和opacity會導致repaint
創建新layer來減少repaint區域。
will-change屬性可以爲元素創建新layer(works in Chrome, Opera and Firefox).或 transform: translateZ(0);(works in all browsers).
過多layer也消耗內存和性能,用Performance判斷新layer是否帶來優化,否則不要創建新layer。
高dpi屏幕下,fixed元素自動擁有自己的layer。低dpi需要自行創建。
repaint某個layer時,如果layer與其他元素重疊,將導致layer和重疊的元素都被repaint。
最好的動畫是跳過layout和paint直接composite。
用transform, opacity來製作動畫,可實現無layout和repaint. (Devtool Performance的main中無動畫相關事件。)
debounce
debounce:不要高頻率調用函數,事件連續觸發時,只調用一次函數。
交互事件的監聽函數的執行時間不能太長,否則會阻塞頁面滾動。
不要再交互事件的監聽函數中修改樣式,會導致強制同步reflow,阻塞js執行。
debounce,活用requestAnimationFrame方法。
監聽函數可能會調用perventDefault, 導致compositor線程必須等待監聽函數執行完成。 不過新擴展的addEventListener方法第三個參數可以解決此問題。
小技巧
動畫不能低於60幀。ui反饋不能低於100ms。
ui反饋不必追求最快,可故意拖延到100ms。並利用這個時間做其他事。
儘量增加線程空閒時間,以快速反饋。
ui反饋優先級最高,交互期間儘量停下其他任務。
原文:https://segmentfault.com/a/1190000013279030?utm_source=channel-newest