前端性能優化分析總結

涉及原理

HTTP協議

三次握手

  • 客戶端發出請求報文;
  • 服務端收到後進行應答,對客戶端的連接請求進行確認;
  • 客戶端收到服務器收到的連接確認請求後再向服務器發送確認信號。

四次揮手

  • 數據傳輸結束後,客戶端向服務器發送斷開連接的請求;
  • 服務器端收到確認報文後進行確認,釋放從客戶端到服務器端這個方向的連接,TCP連接處於半關閉狀態;
  • 服務器向客戶端數據發送完了之後,服務器端向客戶端發送TCP釋放連接請求;
  • 客戶端對服務器斷開請求進行響應,關閉從服務器端到客戶端的連接。
    這裏爲什麼是斷開連接是四次呢,因爲TCP是全雙工通信機制,也就是雙向同時通信

從輸入URL到 頁面渲染完畢,發生了什麼

  1. 瀏覽器解析域名,將URL解析,獲得對於服務器的IP地址;
  2. 瀏覽器與遠程服務器通過TCP三次握手建立連接連接(TCP三次握手);
  3. 建立連接後瀏覽器會通過HTTP GET請求頁面資源
  4. 遠程服務器收到請求,會做邏輯操作,查找數據庫,讀取文件,將資源並通過http響應返回資源;
  5. 瀏覽器開始下載頁面資源,瀏覽器對返回HTML資源進行解析渲染;
  6. 瀏覽器會將HTML解析生成DOM tree,將css解析生成CSSOM,將DOM tree和Css tree合併生成render tree(:after和:before這樣的僞元素會在這個環節被構建到DOM樹中)
  7. 頁面根據生成的Render Tree對元素進行大小、位置計算,繪製到屏幕上
  8. 加載script的js文件,執行js

瀏覽器渲染機制

頁面渲染過程

  1. 解析文件,HTML構建DOM樹
  2. 將css文檔,構建CSSOM樹
  3. 將DOM樹和CSSOM樹合成Render Tree
  4. 計算元素大小、位置,繪製到頁面上

資源加載執行順序

  • 瀏覽器加載HTML頁面是邊下載邊解析,解析順序是自上而下的;
  • 解析過程中發現css文件會並行進行加載,
  • JS: 解析過過程中發現<script>標籤會暫停解析(這裏JS引入方式不包括async和defer),先加載js文件並執行後再繼續解析HTML文檔(因爲JS可以修改DOM樹,這裏(JS的加載和執行)會阻塞HTML頁面的解析從而避免DOM渲染衝突)
  • CSS: 文檔解析的時候遇到css資源會下載樣式文件,不會阻塞DOM的解析;

css文件放於文檔頭部,js文件放於文檔底部,可以讓頁面修改快速下載資源且渲染頁面,並且避免JS執行時DOM節點還沒渲染到頁面會出現執行錯誤

重繪、重排

  • 重繪(repaint):當元素節點的樣式發生改變,但位置及大小不改變,比如改變字體顏色、背景等,對頁面其他節點不造成影響,這時候會觸發瀏覽器重繪;
  • 重排(reflow):當元素節點發生大小、位置發生變化,對其他節點位置造成影響,這時候佈局發生改變,會觸發瀏覽器重排。
    重排會引起重繪,重繪不一定會引起重排(重排較重繪會消耗更多的性能)。

一、文件資源加載優化

1、減少少加載文件數量和體積

  • 代碼(html、js、css)打包壓縮
  • 刪除冗餘代碼:webpack生產環境使用tree-shaking
  • 圖片小圖合併成雪碧圖、使用合適的圖片類型(jpg、png、svg)
  • 使用gzip壓縮內容:服務器設置accept-enconding:gzip 開啓gzip

2、緩存

本地存儲

  • cookie
    cookie可以緩存用戶認證的標誌,設置在某個時間內有效可以不需要多次認證。
    cookie的體積限定,會爲該作用域名下所有請求都帶上所有當前域名的cookie從而造成性能浪費;
  • 靜態資源緩存
    響應頭使用ExpiresCache-Control進行強緩存
    響應問使用協商緩存頭if-modified-sinceetag
  • 使用webStroage緩存數據
    webStroage的localStroage和sessionStroage存儲量大,不自動發送給服務端,js可以操作
  • indexdDB運行在瀏覽器上的非關係型數據庫
    indexdDB是一個key-value型的事務模式的數據庫;
    可以在在線和離線的時候使用,遵從同源協議,所以只能訪問同域中存儲的數據,而不能訪問其他域的;
    可以在瀏覽器端進行數據持久化,可以保存大量數據,在離線的時候也可以訪問;
  • PWA 基於存儲技術的應用模型
    可以Service worker在後頭利用緩存快速加載頁面,消除對網絡的依賴;
    可以通過App Mainfest實現PWA的安裝,將頁面添加至手機屏幕上;
    可以通過Service worker實現消息推送
    通過Service Worker + HTTPS + Cache API + indexedDB實現離線加載和緩存

服務器緩存

比如CDN、Nginx、Apache

2、使用CDN減少用戶與服務器的距離

CDN是內容分發網絡,CDN服務器可以返回最近的緩存服務器給用戶,從而減短下載的鏈路距離從而加快下載速度。同時可以緩存靜態文件。

3、按需加載、懶加載、預加載

  • 按需加載
    在引入組件時可以只引入自己需要的的組件,避免不需要用到的代碼造成內容過多影響下載速度;
    如果是首頁只引入首頁首次加載所必需的的資源,其他可以使用異步的方式稍後加載;

  • 懶加載
    圖片或者其他非首屏需要展示的數據可以使用懶加載,避免加載數據過多阻塞頁面操作;

  • 預加載
    prefetch: 在加載的資源連接加上dns-prefetch標籤,告訴客戶端未來可能會用到的資源,瀏覽器可以今早解析DNS;
    <link rel="dns-prefetch" href="//img.alicdn.com" />

    preconnect: 瀏覽器會提前解析DNS,還會建立tcp連接;
    <link rel="preconnect"href="http://css-tricks.com">
    prefetch: 確認某些資源未來一定會用到,告訴瀏覽器提前請求並緩存好資源。可預拉去圖片、腳本、或者其他可以被緩存的資源。
    <link rel="prefetch" href="need.css">
    圖片預加載:

    	var preloadImgList = [
    	 	'images/1.jpg',
    		'images/2.jpg',
    		'images/3.jpg'
    	];
    	preloadImgList.forEach(function(v) {
    		var img = new Image();
    		img.src = v;
    	});
    

    preload: 指明哪些資源是頁面加載完成後立即需要的,在瀏覽器的主渲染機制介入前就進行預加載。(常用於加載CSS文件)

    //預加載css文件
    <link rel="stylesheet" href="styles/main.css">
    
    // 預加載js,但是並不會執行它
    var preloadLink = document.createElement("link");
    preloadLink.href = "myscript.js";
    preloadLink.rel = "preload";
    preloadLink.as = "script";
    document.head.appendChild(preloadLink);
    
    // 需要執行
    var preloadedScript = document.createElement("script");
    preloadedScript.src = "myscript.js";
    document.body.appendChild(preloadedScript);
    

prefetch 意圖是預獲取一些資源,以備下一個導航/頁面使用(比如,當你去到下一個頁面時),但是對當前頁面沒有什麼助益;瀏覽器會給prefetch的資源一個比較低的優先級;
preload 的資源優先級會比較高(畢竟當前頁面比較重要),更符合當前頁面的優化需求和預期;**

二、代碼層面優化

  • css文件放在文檔頭部,js文件放於頁面底部;
  • 精簡代碼,去掉冗餘代碼
  • 減少DOM操作
    動態插入DOM時可以先把要插入DOM節點緩存起來,一次性插入,避免多次操作DOM導致頁面多次渲染性能消耗;
    修改樣式的時候可以使用class的方式;
  • 節流、防抖:對於連續的事件進行優化,避免連續觸發造成不必要的性能損耗或頁面卡頓;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章