頁面幀(Performance -> FPS,Rendering -> FPS meter)、事件(Performance -> Event Log)和實際內存(Memory,Performance Monitor -> JS heap size)使用三個方面發現程序的問題。
如果一個頁面比較卡,可能是由以下幾方面造成的:
- 內存泄露。使用 Memory 的3次快照查看總內存的增加情況
- JS腳本的執行時間過長。使用 Performance 查看函數的執行時長,定位出具體函數
一、性能監控
1. 最簡單的性能監控:計算首屏加載時間
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript">
// 記錄頁面加載開始時間
var timerStart = Date.now();
</script>
<!-- 加載靜態資源,如樣式資源 -->
</head>
<body>
<!-- 加載靜態JS資源 -->
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
console.log("DOM 掛載時間: ", Date.now() - timerStart);
// 性能日誌上報
});
window.addEventListener('load', function() {
console.log("所有資源加載完成時間: ", Date.now()-timerStart);
// 性能日誌上報
});
</script>
</body>
</html>
2. 用 window.performance 進行性能監控
window.performance 對象可以獲取到當前頁面中與性能相關的信息,是一個做前端性能監控離不開的API,最好在頁面完全加載完成之後再使用,因爲很多值必須在頁面完全加載之後才能得到。最簡單的辦法是在window.onload事件中讀取各種數據。
常用屬性
timeOrigin
返回性能測量開始時的時間戳。
timing(PerformanceTiming)對象
PerformanceTiming 對象包含延遲相關的性能信息,從輸入url到用戶可以使用頁面的全過程時間統計,單位均爲毫秒。
1. navigationStart
表示從同一個瀏覽器上下文的上一個網頁卸載(unload)結束時的時間戳。如果沒有上一個網頁,這個值會和 fetchStart 相同。
2. unloadEventStart
表示前一個網頁(與當前頁面同域)unload 事件處理開始時的時間戳,如果無前一個網頁或者前一個網頁與當前頁面不同域,則值爲 0。
3. unloadEventEnd
和 unloadEventStart 相對應,表示unload
事件處理完成時的時間戳。如果沒有前一個網頁,或者前一個網頁與當前頁面不同域,這個值會返回0。
4. fetchStart
表示瀏覽器準備好使用HTTP請求來獲取(fetch)文檔的時間戳。這個時間點會在檢查任何應用緩存之前。
5. requestStart
返回瀏覽器向服務器發出HTTP請求時(或開始讀取本地緩存時)的時間戳。
6. responseStart
返回瀏覽器從服務器收到(或從本地緩存讀取)第一個字節時的時間戳。
7. responseEnd
返回瀏覽器從服務器收到(或從本地緩存讀取,或從本地資源讀取)最後一個字節時(如果在此之前HTTP連接已經關閉,則返回關閉時)的時間戳。
8. domLoading
返回當前網頁DOM結構開始解析時(即 document.readyState 屬性變爲“loading”、相應的 readystatechange
事件觸發時)的時間戳。
9. domInteractive
返回當前網頁DOM樹結束解析、開始加載內嵌資源時(即Document.readyState
屬性變爲“interactive”、相應的readystatechange
事件觸發時)的時間戳。
注意: 只是 DOM 樹解析完成,這時候並沒有開始加載網頁內的資源。
10. domContentLoadedEventStart
返回 DOM 解析完成後,網頁內資源加載開始的時間,文檔發生 DOMContentLoaded 事件的時間。
11. domContentLoadedEventEnd
返回 DOM 解析完成後,網頁內資源加載完成的時間(如 JS 腳本加載執行完畢),文檔的DOMContentLoaded 事件的結束時間。
12. domComplete
返回當前文檔解析完成,即Document.readyState
變爲 'complete'且相對應的
readystatechange
被觸發時的時間戳。
13. loadEventStart
返回該文檔下,load
事件被髮送時的時間戳。如果這個事件還未被髮送,它的值將會是0。
14. loadEventEnd
返回當load
事件結束,即加載事件完成時的時間戳。如果這個事件還未被髮送,或者尚未完成,它的值將會是0。
// 計算加載時間
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 樹結構的時間
//【原因】反省下你的 DOM 樹嵌套是不是太多了!
times.domReady = t.domComplete - t.domInteractive;
//【重要】重定向的時間
//【原因】拒絕重定向!比如,http://example.com/ 就不該寫成 http://example.com
times.redirect = t.redirectEnd - t.redirectStart;
//【重要】DNS 查詢時間
//【原因】DNS 預加載做了麼?頁面內是不是使用了太多不同的域名導致域名查詢的時間太長?
// 可使用 HTML5 Prefetch 預查詢 DNS ,見:[HTML5 prefetch](http://segmentfault.com/a/1190000000633364)
times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
//【重要】讀取頁面第一個字節的時間
//【原因】這可以理解爲用戶拿到你的資源佔用的時間,加異地機房了麼,加CDN 處理了麼?加帶寬了麼?加 CPU 運算速度了麼?
// TTFB 即 Time To First Byte 的意思
// 維基百科:https://en.wikipedia.org/wiki/Time_To_First_Byte
times.ttfb = t.responseStart - t.navigationStart;
//【重要】響應耗時
//【原因】頁面內容經過 gzip 壓縮了麼,靜態資源 css/js 等壓縮了麼?
times.request = t.responseEnd - t.responseStart;
//【重要】執行 onload 回調函數的時間
//【原因】是否太多不必要的操作都放到 onload 回調函數裏執行了,考慮過延遲加載、按需加載的策略麼?
times.loadEvent = t.loadEventEnd - t.loadEventStart;
// DNS 緩存時間
times.appcache = t.domainLookupStart - t.fetchStart;
// 卸載頁面的時間
times.unloadEvent = t.unloadEventEnd - t.unloadEventStart;
// TCP 建立連接完成握手的時間
times.connect = t.connectEnd - t.connectStart;
// 白屏時間
times.domContentLoaded = t.domContentLoadedEventEnd - t.navigationStart;
return times;
}
navigation (PerformanceNavigation
)對象
呈現瞭如何導航到當前文檔的信息。
1. type
表示是如何導航到這個頁面的。
type 值 | 描述 |
---|---|
0 | 普通進入,包括:點擊鏈接、書籤、在地址欄中輸入 URL、表單提交、或者通過除下表中 1 和 2 的方式初始化腳本。 |
1 | 通過刷新進入,包括:瀏覽器的刷新按鈕、快捷鍵刷新、location.reload()等方法。 |
2 | 通過操作歷史記錄進入,包括:瀏覽器的前進後退按鈕、快捷鍵操作、history.forward()、history.back()、history.go(num)。 |
255 | 其他非以上類型的方式進入 |
2. redirectCount
表示在到達這個頁面之前重定向了多少次(這個接口有同源策略限制,即僅能檢測同源的重定向)。
memory 對象
memory 是非標準屬性,只在 Chrome 有,這個屬性提供了一個可以獲取到基本內存使用情況的對象。
jsHeapSizeLimit
: 內存大小限制totalJSHeapSize
: 可使用的內存usedJSHeapSize
: JS對象(包括V8引擎內部對象)佔用的內存,不能大於totalJSHeapSize,如果大於,有可能出現了內存泄漏
onresourcetimingbufferfull 方法
它是一個在resourcetimingbufferfull
事件觸發時會被調用的event handler
。這個事件當瀏覽器的資源時間性能緩衝區已滿時會觸發。可以通過監聽這一事件觸發來預估頁面crash
,統計頁面crash
概率,以便後期的性能優化,如下示例所示:
function buffer_full(event) {
console.log("WARNING: Resource Timing Buffer is FULL!");
performance.setResourceTimingBufferSize(200);
}
function init() {
// Set a callback if the resource buffer becomes filled
performance.onresourcetimingbufferfull = buffer_full;
}
<body οnlοad="init()">