性能調試實踐

頁面幀(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()">

 


 

 

 

 

 

發佈了122 篇原創文章 · 獲贊 87 · 訪問量 52萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章