Chrome Dev Tools 之 Performance
作為前端開發,肯定對 Chrome 的 dev tools 不陌生,除了日常 Debug,還提供了一個非常強大的功能:performance 用做性能分析。
window.performance 提供了一組精确的資料,配合資料上報即可實作簡單的性能統計。
1. 屬性字段
首先可以打開官方提供的測試頁:<https://googlechrome.github.io/devtools-samples/jank/>,在 Chrome 控制台下輸入
window.performance
即可得到 performance 屬性字段。

01.png
var performance = {
// memory 記憶體 ( only Chrome )
memory: {
usedJSHeapSize: 17045133, // JS對象占用的記憶體
totalJSHeapSize: 18463485, // 可使用的總記憶體
jsHeapSizeLimit: 2197815296 // 記憶體大小限制
},
// navigation 導航
navigation: {
redirectCount: 0, // 重定向次數
type: 0 // 0 TYPE_NAVIGATENEXT 正常進入的頁面(非重新整理、非重定向等)
// 1 TYPE_RELOAD 通過 window.location.reload() 重新整理的頁面
// 2 TYPE_BACK_FORWARD 通過浏覽器的前進後退按鈕進入的頁面
// 255 TYPE_UNDEFINED 非以上方式進入的頁面
},
// timing 時間
timing: {
// 前一個網頁 unload 的時間戳
navigationStart: 1573989694438,
// 前一個網頁(與目前頁面同域) unload 開始的時間戳
unloadEventStart: 0,
// 前一個網頁(與目前頁面同域) unload 結束的時間戳
unloadEventEnd: 0,
// 第一個 HTTP 重定向發生時的時間。有跳轉且是同域名内的重定向才算,否則值為 0
redirectStart: 0,
// 最後一個 HTTP 重定向完成時的時間。有跳轉且是同域名内部的重定向才算,否則值為 0
redirectEnd: 0,
// 浏覽器準備好使用 HTTP 請求抓取文檔的時間
fetchStart: 1573989694445,
// DNS 域名查詢開始的時間
domainLookupStart: 1573989694445,
// DNS 域名查詢完成的時間
domainLookupEnd: 1573989694445,
// HTTP 開始建立連接配接的時間
connectStart: 1573989694445,
// HTTP 完成建立連接配接的時間
connectEnd: 1573989694445,
// HTTPS 連接配接開始的時間
secureConnectionStart: 0,
// HTTP 請求完成建立連接配接
requestStart: 1573989694564,
// HTTP 開始接收響應的時間
responseStart: 1573989694605,
// HTTP 響應全部接收完成的時間
responseEnd: 1573989694618,
// DOM 樹開始解析渲染
domLoading: 1573989694688,
// DOM 解析完成,資源未加載的時間
domInteractive: 1573989696189,
// DOM 解析完成,資源加載開始的時間
domContentLoadedEventStart: 1573989696189,
// DOM 解析完成,網頁内資源加載完成的時間
domContentLoadedEventEnd: 1573989696330,
// DOM 解析完成,且資源準備就緒的時間
domComplete: 1573989697523,
// load 事件回調函數開始執行的時間 (若未綁定 load 事件,值為 0)
loadEventStart: 1573989697531,
// load 事件回調函數執行完畢的時間
loadEventEnd: 1573989697553
}
};
複制
2. 常用性能資料名額計算
02.png
封裝常用性能名額統計函數
// 計算加載時間
function getPerformanceTiming () {
var performance = window.performance;
if (!performance) {
console.log('你的浏覽器不支援 performance 接口');
return;
}
var t = performance.timing;
var times = {};
// * 使用者等待整個頁面加載完成的時間
times.loadPage = t.loadEventEnd - t.navigationStart;
// * DOM 樹解析時間
times.domReady = t.domComplete - t.responseEnd;
// * 重定向的時間
times.redirect = t.redirectEnd - t.redirectStart;
// * DNS 解析時間
times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
// * 白屏時間 TTFB (Time To First Byte) ? cdn
times.ttfb = t.responseStart - t.navigationStart;
// * 内容加載完成的時間 ? gzip 檔案壓縮
times.request = t.responseEnd - t.requestStart;
// 執行 onload 回調函數的時間 ? onload回調函數執行過多,延遲加載、懶加載
times.loadEvent = t.loadEventEnd - t.loadEventStart;
// DNS 緩存時間 (App Cache)
times.appcache = t.domainLookupStart - t.fetchStart;
// 解除安裝頁面的時間
times.unloadEvent = t.unloadEventEnd - t.unloadEventStart;
// TCP 連接配接時間
times.connect = t.connectEnd - t.connectStart;
return times;
}
複制
3. 其他 api
3.1 performance.getEntries()
傳回值為所有資源的加載情況的數組,除了
performance.timing
中包含的部分屬性,新增四個屬性:
name: "http://cdn.xxx/xxx.css", // 資源名稱(絕對路徑)
entryType: "resource", // 資源類型
initiatorType: "link", // link => <link>标簽
// script => <script>标簽
// redirect => 重定向
duration: 18.00099999999999 // 加載時間
複制
封裝擷取對某個資源的加載情況:
function getEntryTiming (entry) {
var t = entry;
var times = {};
// 重定向時間
times.redirect = t.redirectEnd - t.redirectStart;
// DNS查詢時間
times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
// 内容加載完成的時間
times.request = t.responseEnd - t.requestStart;
// TCP 建立連接配接完成握手的時間
times.connect = t.connectEnd - t.connectStart;
// 新增屬性
times.name = entry.name;
times.entryType = entry.entryType;
times.initiatorType = entry.initiatorType;
times.duration = entry.duration;
return times;
}
複制
3.2 performance.now() / performance.mark()
精确計算程式執行時間,
performance.now()
傳回以微秒為機關的時間,更加精準,而且
Date.now()
可能受系統時間影響且可能阻塞,而
performance.now()
輸出的是相對于
performance.timing.navigationStart
(頁面初始化) 的時間,而
performance.mark()
則可以在程式中進行時間打點存儲,以便後面分析。
performance.now()
function getFunctionTimeWithPerformance (func) {
var timeStart = window.performance.now();
func();
var timeEnd = window.performance.now();
return (timeEnd - timeStart);
}
複制
performance.mark()
function randomFunc (n) {
if (!n) {
n = ~~(Math.random() * 10000); // 生成一個随機數
}
var nameStart = 'markStart' + n;
var nameEnd = 'markEnd' + n;
var name = 'measureRandomFunc' + n;
// 函數執行前做标記
window.performance.mark(nameStart);
for (var i = 0; i < n; i++) {
// do nothing
}
// 函數執行後再做标記
window.performance.mark(nameEnd);
// 測量這個兩個标記的時間距離,并儲存
window.performance.measure(name, nameStart, nameEnd);
}
randomFunc();
randomFunc(888);
// 檢視儲存的标記
var marks = window.performance.getEntriesByType('mark');
var measure = window.performance.getEntriesByType('measure');
var entries = window.performance.getEntriesByName('measureRandomFunc888'); // 檢視自定義測量
console.log(marks,measure,entries);
// 清除标記
window.performance.clearMarks('markStart888'); // 清除指定标記
window.performance.clearMarks(); // 清除所有标記
window.performance.clearMeasures('measureRandomFunc');
window.performance.clearMeasures();
複制
使用
measure
計算 domReady 時間
// 舊方案
var t = performance.timing
var domReadyTime = t.domComplete - t.responseEnd;
console.log(domReadyTime)
// 新方案
window.performance.measure('domReady','responseEnd','domComplete');
var domReadyMeasure = window.performance.getEntriesByName('domReady');
console.log(domReadyMeasure);
複制
3.3 performance.memory
檢視浏覽器記憶體情況,包含:
-
:記憶體大小限制jsHeapSizeLomit
-
:可使用的記憶體totalJSHeadSize
-
:已使用的記憶體userdJSHeadSize
參考:
https://developers.google.cn/web/tools/chrome-devtools/network/understanding-resource-timing