Node端效能
效能評估
-
通過效能測試工具評估:
- wrk:支援lua指令碼,可以輕鬆應對各種測試需求,如
-- 帶隨機引數請求 function request() wrk.headers["Connection"] = "keep-Alive" arg = math.random(1, 500) path = "/random?arg=" .. arg return wrk.format("GET", path) end 複製程式碼
-
通過v8 profiling檢視程式執行過程資料,與Webstorm聯合使用,可以在Webstorm【Run/Debug Configurations】裡面配置,注意需要先安裝:v8-profiler
常見優化方案
- 併發請求,例如:promise.all併發三方HTTP介面呼叫、RPC呼叫
- 如果用到mysql
- 使用資料庫連線池,重用連線
- 常用查詢建立索引
- 用程式避免聯合查詢
- 讀寫分離
- 加入快取策略
前端效能
DNS查詢
- 減少DNS查詢次數
TCP/HTTP
優化核心
- 消除和減少不必要的網路延遲
- 把傳輸位元組數降到最少
具體步驟
- 減少HTTP請求:對於HTTP1.0/1.1 減少請求資源數(打包、壓縮、合併等)
- 使用CDN
- 新增Expires首部並配置ETag標籤
- GZip資源
- 避免HTTP重定向
- 持久化連線:避免TCP的三次握手,HTTP1.1預設開啟,HTTP1.0可以使用:Connection: Keep-Alive
- HTTP1 不支援多路複用,可以為一臺主機並行開啟多個TCP會話(一般為6個)
- 消除不必要的請求位元組(HTTP1 請求、響應頭不會被壓縮)
- 嵌入資源,如:Base64嵌入資源(針對小的靜態圖片資源)
客戶端渲染
關鍵渲染路徑:DOM -> CSSDOM / JS -> RenderTree -> Layout -> Paint
瀏覽器渲染過程
構建DOM
- 構建過程:character -> token -> node -> DOM
- 增量構建
構建CSSOM(CSS Object Model)
- 構建過程:character、token、node、CSSOM
- 選擇器越複雜,匹配用的時間約多
構建RenderTree
- RenderTree包含所有需要呈現在頁面上的節點資訊
- display: none的元素不會被新增到RenderTree中,因為它不需要被渲染,visibility: hidden的元素會被新增到RenderTree中
Layout
- 計算需要渲染的節點的大小和位置
- 節點位置和大小是基於將viewport計算的
- 在移動端通常將viewport設定為瀏覽器推薦的理想視口,以保證字型顯示大小易於閱讀
- 旋轉螢幕、修改瀏覽器視窗大小,修改位置大小相關的CSS屬性,都可能觸發Layout
Paint
- 根據background、border、box-shadow等樣式,將Layout生成的區域填充為最終將顯示在螢幕上的畫素
資源優化
CSS效能優化(防止資源阻塞初次渲染)
- media query(link裡面加上media)
- 此時樣式表仍然會載入,當瀏覽器環境不匹配媒體查詢條件時,該樣式表不會阻塞渲染
- 針對不同媒體環境拆分CSS檔案,避免為了載入非關鍵CSS資源,而阻塞初次渲染
- 使用DOM API新增link不會阻塞初次渲染
var style = document.createElement('lin');
style.rel = 'stylesheet';
style.href = 'index.css';
document.head.appendChild(style);
複製程式碼
- preload & prefetch & prerender(不止可以用於CSS)
- rel="preload",不是stylesheet不會阻塞渲染
- preload是resource hint規範中定義的一個功能,resource hint告知瀏覽器提前建立連線或載入資源,以提高資源載入的速度:
- preload:https://www.w3.org/TR/preload/
- prefetch & prerender:https://w3c.github.io/resource-hints/#prefetch
- 瀏覽器遇到標記為preload的link時,會開始載入它
- 當onload事件發生時,將rel改為stylesheet,即可應用此樣式
- 可以通過 loadCSS.js 使用preload (CSS preload polyfill):原理其實就是使用DOM API
<link rel="preload" type="text/css" href="./style.css" as="style" onload="this.rel='stylesheet'"/>
複製程式碼
JS效能優化
- JS會阻塞HTML Parse(HTML解析器,增量),因而會阻塞出現在指令碼後面的HTML標記的渲染
- 原因:JS可以通過document.write修改HTML文件流,因此在執行JS時,瀏覽器會暫停解析DOM的工作
- CSS會阻塞JS
- 瀏覽器資源載入策略(preload,與前面CSS preload不一樣,詳見:https://juejin.im/post/5a4ed917f265da3e317df515)
- 當HTML Parser被指令碼阻塞時,Parser雖然會停止構建DOM,但仍會識別該指令碼後面的資源,並提前載入
- 效能優化(防止阻塞)
- 將資源放到body底部
- 使用defer延遲指令碼執行:使用defer,該指令碼會被推遲到整個HTML文件解析完後,再開始執行。被defer的指令碼,在執行時會嚴格按照在HTML文件中出現的順序執行。使用defer方法,可以提早指令碼資源載入
- 使用async非同步載入指令碼:該指令碼不會阻塞HTML parser,也不會被CSS阻塞,指令碼載入完就開始執行。async適用於無依賴的獨立資源(比如百度統計程式碼)
圖片
- 使用blob非同步載入
- 使用img-2代替img標籤(原理與上面一樣),對於圖片多的網站輕鬆提升五倍以上訪問速度
字型
- 瀏覽器為了避免FOUT(Flash Of Unstyled Text),會盡量等待字型載入完成後,再顯示應用了該字型的內容。帶來了FOIT(Flash Of Invisible Text 問題),導致空白
- 設定多字型,降級方法:使用預設字型
- 非同步載入字型檔案:通過非同步載入CSS,即可避免字型阻塞渲染,還是會空白
其它
- 按需載入/懶載入
- 對於React技術棧,推薦使用next.js prefetch
優化關鍵渲染路徑
優化目標
- 關鍵資源數
- 關鍵資源體積
- 關鍵資源網路來回數
勿盲目內聯資源
- 若啟用HTTP2,則無需內聯資源
- 若資源被多個頁面共享,則無法充分利用快取,導致重複得下載
內聯與快取結合
- 首次訪問,使用內聯,並通過非同步(如:rel="prefetch")請求快取資源,快取成功通過cookie標記,下次訪問時,則只返回外部資源標記
其它
常用工具
效能測試工具
相關資料
補充
TTFB(Time To First Byte):
- 從客戶端發出請求到接收到第一個響應位元組所花費時間(Transfer-Encoding: chunked)
HTTP2.0主要設計:
- 解決HTTP中“隊首阻塞”;
- 二進位制分幀機制,無需建立多個TCP連線,從而改進TCP利用率
- 保持HTTP1.1語義
隊首阻塞:
- HTTP應用層隊首阻塞:按照優先順序傳送請求
- TCP傳輸層隊首阻塞:TCP要求分組嚴格按照順序交付