前端極致性能優化手冊大全

前端極致性能優化手冊大全

原文鏈接

前端優化之路必不可少的知識點。

  • 瀏覽器輸入url到頁面的展現,具體發生了些什麼,前端能做哪些優化
  1. DNS 遞歸查詢解析 —— DNS優化prefetch;
  2. TCP 三次握手、四次揮手 —— http1.0/1.1/2.0 的區別,http/s的區別;
  3. http 緩存 —— 304 與 CDN;
  4. 瀏覽器渲染機制 —— CSS、JS順序的重要性,@import的損耗,防抖、節流、重排、重繪,GPU加速等;
  5. 如何優化JS主線程 —— web worker,時間分片
  • 圖片你優化了嗎,雪碧圖、webp、svg;
  • webpack 等打包優化
  • 運維的基本知識 nginx

本文按一定順序總結與前端性能優化的基本點,大家可以按步驟逐一檢查自己的項目,找出性能的瓶頸。如有錯誤遺漏歡迎補充糾正。

文章有些原理細節都在參考文章中,價值較高建議讀一讀。

webpack

默認的 webpack4 很多優化內部已經做到很好了,但無法滿足所有的業務場景,
如果發現開發時打包慢、打包體積太大,這是你就要審視下配置了。

代碼分塊分析插件 webpack-bundle-analyzer

npm i webpack-bundle-analyzer -D
  • 修改 webpack.config.js
// 在頭部添加
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

// 在plugins: [] 中新增配置如下
new BundleAnalyzerPlugin({
  analyzerMode: 'server',
  analyzerHost: '127.0.0.1',
  analyzerPort: 8000,
  reportFilename: 'report.html',
  defaultSizes: 'parsed',
  openAnalyzer: true,
  generateStatsFile: false,
  statsFilename: 'stats.json',
  statsOptions: null,
  logLevel: 'info'
})
  • 啓動本地開發服務,瀏覽器中打開 http://127.0.0.1:8000

webpack-bundle-analyzer

  • webpack4 默認代碼分割策略
  1. 新的 chunk 是否被共享或者是來自 node_modules 的模塊
  2. 新的 chunk 體積在壓縮之前是否大於 30kb
  3. 按需加載 chunk 的併發請求數量小於等於 5 個
  4. 頁面初始加載時的併發請求數量小於等於 3 個

比如,由於業務中頻繁 antd 中的UI組件,但他們都小於 30kb 不會被獨立打包,導致過多重複的代碼打入不同 chunk 中。
這時根據實際業務情況,默認的配置就不滿足需求了。修改策略:

  1. react 全家桶和狀態管理一個 vendor
  2. antd 相關的一個 lib
  3. node_modules 裏的打成 common
// 默認配置
splitChunks: {
  chunks: 'all',
  name: false,
}

// 修改後的配置
splitChunks: {
  chunks: 'all',
  name: false,
  cacheGroups: {
    vendor: {
      name: 'vendor',
      test: module = >/(react|react-dom|react-router-dom|mobx|mobx-react)/.test(module.context),
      chunks: 'initial',
      priority: 11
    },
    libs: {
      name: 'libs',
      test: (module) = >/(moment|antd|lodash)/.test(module.context),
      chunks: 'all',
      priority: 14
    },
    common: {
      chunks: "async",
      test: /[\\/] node_modules[\\ / ] / ,
      name: "common",
      minChunks: 3,
      maxAsyncRequests: 5,
      maxSize: 1000000,
      priority: 10
    }
  }
}

結論:

  • 優化前體積爲56MB(去除sourceMap)
  • 優化後體積爲36MB(保留sourceMap,去除sourceMap大約在7.625MB)

glob 和 purgecss-webpack-plugin 去除無用CSS

npm i glob purgecss-webpack-plugin -D
// 在webpack.config.js中的plugins: []中添加.
// 需要注意的是paths一定要是絕對路徑,比如antd的樣式不在src目錄下就需要寫成一個數組,要不然antd的樣式就會不見了
new purgecssWebpackPlugin({
  paths: glob.sync(`${paths.appSrc}/**/*`, { nodir: true })
})

結論:CSS資源減小很多

一番操作下來

  • 目前資源已經減小到7.25M左右;
  • 打包速度由7.5分鐘減少到2.5分鐘,效率極大提升。

圖片

webp

webp 是一種新式圖片格式,在保證品質的同時提供無損和有損壓縮。
webp 對於圖片較多的站點是必不可少的優化手段,一般 CDN 都有提供轉換服務。

  • 某寶大規模使用

webp

  • 優點:在同等品質下,無損圖片比 png 減少 26% 的大小,有損下比 jpeg25-34%
  • 缺點:有的瀏覽器不兼容,需要做兼容,以下是官方提供
// check_webp_feature:
//   'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
//   'callback(feature, result)' will be passed back the detection result (in an asynchronous way!)
function check_webp_feature(feature, callback) {
    var kTestImages = {
        lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",
        lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
        alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
        animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
    };
    var img = new Image();
    img.onload = function () {
        var result = (img.width > 0) && (img.height > 0);
        callback(feature, result);
    };
    img.onerror = function () {
        callback(feature, false);
    };
    img.src = "data:image/webp;base64," + kTestImages[feature];
}

雪碧圖

多個圖片拼成一個圖片,在利用 background-position 定位。
減少 http 請求。

HTTP2 可以解決線頭阻塞問題。

iconfont

svg 版雪碧圖

base64

// 字符轉
window.btoa('str');
// canvas 轉
canvas.toDataURL();
// 圖片轉
const reader = new FileReader();
const imgUrlBase64 = reader.readAsDataURL(file);
// webpack 打包轉
// url-loader 
  • 優點:便於存儲在html、js中,減少http請求個數。
  • 缺點:文件尺寸增大 30% 左右。

適用於少量小圖的場景。

緩存

DNS緩存

查找過程

  1. 先瀏覽器 DNS 緩存
  2. 查找 hosts 文件域名 IP 映射(你知道背牆DNS污染但沒封的IP,可以設置hosts文件訪問)
  3. 查找本地 DNS解析器(路由) 緩存
  4. 根DNS服務器 -> 頂級.com -> 二級域名服務器xx.com -> 主機 www.xx.com
  • 可以看出某些 DNS 解析佔大頭時間,優化還是很有必要的

DNS

  • dns-prefetch,例如訪問某寶首頁,猜測你接下來要訪問某些域名,提前去解析。以節省下個頁面的 DNS 查詢。
    不過大量不必要的預獲取,對公共網絡資源造成較大浪費。

dns-prefetch

  • 優化後

dns-better

http 緩存

http 緩存

簡單提下,對於現在 SPA 項目,一般靜態資源放在 CDN 上,
對經常變動入口文件index.html 設置強制檢驗過期 Cache-Control: no-cahce 或直接不緩存。
其他 hash 命名的資源直接設置長緩存(max-age: 一年半載)。

具體詳情已在另一篇文字闡釋,文末鏈接。

CDN(Content Delivery Network) 內容分發網絡

優點:

  1. 資源文件多處備份,就近原則,網絡離用戶最近的服務器提供服務,速度快、安全性高;
  2. 帶寬貴啊,大量的用戶訪問,不上 CDN ,網站很卡或崩潰。

本地緩存 localStorage、sessionStorage、cookie

  • storage
  1. localStorage 一直存在瀏覽器中,要麼用戶刪除或瀏覽器緩存策略剔除
  2. sessionStorage 頁面關閉消失

優點:可以存儲較大的數據 Chrome 5M

  • cookie

相比 storage

  1. 優點:可以設置失效時間
  2. 缺點:存儲量較小,http1.x 每次會上報給服務器,造成網絡浪費。

建議:對服務器安全數據設置 http-only,能少用盡量少用,只用來與服務器進行狀態維護和用戶識別。

瀏覽器渲染

CSS

  • 減少 @import 的使用,瀏覽器解析 html 會優化嗅探獲併發獲取文件,如果使用 @import 需要下載解析了當前 CSS 文件,才能下載。
  • CSS 權重較高,應該優先下載解析。

腳本 defer、async

只對外聯腳本有效。衆所周知,腳本解析會阻塞 DOM 解析,這兩個屬性就是爲了解決這個問題。

  • defer 下載時不阻塞 HTML 解析成 DOM,下載完成會等待 DOM 構建完畢且在 DOMContentLoaded 事件觸發之前執行,多個 defer 腳本保證腳本執行順序。

  • async 下載時不阻塞 HTML 解析成 DOM,下載完畢後儘量安排JS執行。意思說執行時間不確定,早下載早執行。如果 DOM 未構建完,腳本可能會阻塞DOM構建。

  • 例如某寶大量在頭部使用 async

async

  • 但不是很理解是,按原理 async 應該用在對 DOM構建 和腳本順序無依賴的場景,而且下載太快還可能阻塞 DOM構建。感覺 defer 更合適。

防抖、節流

在其他文章有詳細說明,在此不再贅述,請看參考索引。

防止強制佈局

  • 主要是在避免在循環中又讀又寫樣式

FSL

GPU 加速

  1. will-change: transform
  2. transform: translateZ(0)

會單獨把元素提升層級交給 GPU 渲染,適合一些 Animation 動畫。

requestAnimation, requestIdelCallback

  • google 文檔上有很多探討,檢測計算長任務的新 api 進展。
  • Facebook 最新 react 中的 fiber 調度,就使用了 requestAnimation, requestIdelCallback
    進行長任務的時間切片,避免以前深 DOM 樹更新產生長耗時甚至抖動。

main-thread

web worker

對於需要大量計算會佔用渲染主線程,適合放到 web worker 來執行。

服務器

http2

http1.1 對比 http 1.0 主要進步有

  1. 緩存處理的增強,如 Etag
  2. 加入 range頭,響應碼206(Partial Content) 支持斷點續傳
  3. 加入 host 頭,多個域名可以綁定一個 IP
  4. 響應頭 Connection: keep-alive,長連接,客戶端與同一個主機通信不必多次 三次握手

https 與 http

  1. https 需要申請 CA 證書,要錢;https 在 http 上多了層安全協議 SSL/TLS
  2. 客戶端進行 CA 認證,連接需要非對稱加密(耗時),傳輸數據使用對稱加密;
  3. 防止運營商 http 劫持,插廣告等。http 端口 80,https 443

http2 對比 http1.x

  1. header壓縮,例如後者每次傳輸數據都得帶很多相同的頭部信息,http2 會壓縮頭部且避免重複頭部重傳;
  2. 新的二進制格式,後者是基於文本協議解析,前者基於01串,方便且健壯;
  3. 多路複用,注意與 keep-alive 區分。前者是連接共享,每個請求有個唯一 id 來確認歸屬,多個請求可以同時相互混雜。
    而後者減少了握手保持長聯,會影響服務器性能,先進先出需要等前一個請求發完才能進行下一個,造成線頭阻塞。客戶端一般會限制一個頁面與不同服務器同時http連接上限;
  4. 服務器推送,http1.x服務器只能被動接收請求發送資源,HTTP2可以主動推送。

http2 可以提升傳輸效率。nginx 有必要做好 http2 的升級和降級處理。

gzip

服務器開啓壓縮,文本類型的文件能夠減少網絡傳輸。
特別是文件較大且重複率高的文本壓縮效果更明顯。

如圖 index.html 文件壓縮 (383-230)/383=39.95%

gzip

  1. Chrome request headers 告訴服務器支持的壓縮算法:Accept-Encoding: gzip, deflate, br
  2. 服務器響應使用的壓縮算法 response headers:Content-Encoding: gzip
  • nginx 開啓
gzip on;
// 不壓縮臨界值,大於1K的才壓縮,一般不用改
gzip_min_length 1k; 
// 壓縮級別,1-10,數字越大壓縮的越細,時間也越長
gzip_comp_level 2;
// 進行壓縮的文件類型
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
// ie兼容性不好所以放棄
gzip_disable "MSIE [1-6]\.";

compression-webpack-plugin 配合 gzip

npm i compression-webpack-plugin -D
const CompressionWebpackPlugin = require('compression-webpack-plugin');

// 在webpack.config.js中的plugins: []中添加.
new CompressionWebpackPlugin({
  asset: '[path].gz[query]', // 目標文件名       
  algorithm: 'gzip',		 // 使用gzip壓縮        
  test: /\.(js|css)$/, 		 // 壓縮 js 與 css       
  threshold: 10240,			 // 資源文件大於10240B=10kB時會被壓縮        
  minRatio: 0.8 			 // 最小壓縮比達到0.8時纔會被壓縮   
})
  • 優點
    nginx 開啓 gzip,發現有壓縮好的 gzip 壓縮文件,就會直接使用,減少服務器 cpu 的資源的使用。
  • 缺點
    打包時間就會拉長。現在靜態資源一般會上CDNgzip 是CDN服務器基本的服務,
    需要去節省本就花了錢買的服務器資源,而增加打包的時間嗎?

es6、動態使用POLYFILL

webpack 默認支持 es6 的新特性 tree-shaking,可以搖掉不用的代碼,且新api的性能很高。
推薦全面使用。

// 會根據ua返回不同的內容
https://polyfill.io/v3/polyfill.min.js
方案 優點 缺點
babel-polyfill React 官方推薦 體積200kb
babel-plugin-transform-runtime 體積小 不能poyfill原型上的方法
polyfill-service 動態根據ui加載 兼容性,國內部分瀏覽器有問題

結論:可以減少資源大小,但依賴外部服務,自建麻煩的話,放棄。

參考

  1. 從優化到面試裝逼指南——網絡系列

瀏覽器渲染

  1. 防抖debounce 與 節流throttle
  2. 如何構建 60FPS 應用
  3. 一幀剖析
  4. 性能優化——關鍵路徑渲染優化

webpack

  1. 手摸手,帶你用合理的姿勢使用webpack4(下)

http相關

  1. HTTP 緩存
  2. TCP的三次握手與四次揮手(詳解+動圖)
  3. HTTP1.0、HTTP1.1 和 HTTP2.0 的區別
  4. nginx 完整配置
  5. DNS遞歸查詢與迭代查詢

iconfont

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