前端效能監控:你瞭解 Performance Timeline Level 2 嗎?

samciu發表於2019-04-13

什麼是 Performance Timeline?

Performance Timeline是W3C效能小組提出的一個規範,定義了讓開發者在應用整個生命週期內收集各種效能指標的介面。

最新的Performance Timeline Level 2標準,取代了第一版Performance Timeline標準,它包括了以下三點:

  • 擴充套件了Performance介面的基本定義
  • 在Web Workers中暴露了PerformanceEntry
  • 增加了PerformanceObserver的支援

Performance Timeline 在 Node.js

值得注意的是,在Node.js裡同樣遵循W3C的Performance Timeline規範,實現了 Performance Hooks 介面。Performance Hooks 的API和現代瀏覽器中實現的 Performance API 是一致的。

在瀏覽器中,我們可以使用 window 物件取得window.performancewindow.PerformanceObserver ,而在 Node.js 程式中需要 perf_hooks 取得效能物件,如下:

const { PerformanceObserver, performance } = require('perf_hooks');
複製程式碼

瀏覽器相容性

  • performance在瀏覽器中的相容性
    前端效能監控:你瞭解 Performance Timeline Level 2 嗎?
  • PerformanceObserver在瀏覽器中的相容性
    PerformanceObserver相容性

W3C效能小組鼓勵開發人員在瀏覽器相容性允許的情況下,儘可能使用 PerformanceObserver。另外,新的效能API和指標可能只能通過PerformanceObserver 介面獲得。

performance 和 PerformanceObserver 的使用

window.performance

使用window.performance,我們可以這樣去度量某個函式的效能。

    function init() {
      performance.mark("startWork");
      doWork(); 
      performance.mark("endWork");
      performance.measure("work", "startWork", "endWork")
      measurePerf();
    }
    function measurePerf() {
      performance
        .getEntries()
        .map(entry => JSON.stringify(entry, null, 2))
        .forEach(json => console.log(json));
    }
複製程式碼

在上述程式碼中,我們使用了performance.markperformance.measure來記錄效能記錄的資料。

performance.measure方法會根據 startMark 和 endMark 對應的,由 performance.mark產生的兩條記錄,來產生一條 entryType 為 'measure' 的新記錄,並計算執行時長。

然後程式碼裡使用了performance.getEntries來獲取瀏覽器緩衝區中所有的效能資料記錄。

當然,我們也可以使用performance.getEntriesByName獲取指定 entryType 的效能記錄。

window.PerformanceObserver

正如上文所述,我們要想獲得某項效能記錄,需要知道指定的效能事件已經發生(或者使用定時輪訓的方式),主動呼叫performance.getEntries或者performance.getEntriesByName來獲得。

為了解決這個問題,在Performance Timeline Level 2中,除了擴充套件了Performance的基本定義以外,還增加了PerformanceObserver介面。

顧名思義,PerformanceObserver在瀏覽器內部對Performance實現了觀察者模式,也是現代瀏覽器支援的幾個 Observer 之一。

它解決了以下3點問題:

  • 避免不知道效能事件啥時候會發生,需要重複輪訓timeline獲取記錄。
  • 避免產生重複的邏輯去獲取不同的效能資料指標
  • 避免其他資源需要操作瀏覽器效能緩衝區時產生競態關係。

在相容Performance Timeline Level 2的瀏覽器或者 Node.js 中,可以這樣寫:

const userTimingObserver = new PerformanceObserver(list => {
  list
    .getEntries()
    .map(({ name, entryType, startTime, duration }) => {
      const obj = {
        "Duration": duration,
        "Entry Type": entryType,
        "Name": name,
        "Start Time": startTime,
      };
      return JSON.stringify(obj, null, 2);
    })
    .forEach(console.log);
  userTimingObserver.disconnect();
});
userTimingObserver.observe({entryTypes: ["mark", "measure"]});
複製程式碼

另外有必要介紹一下 performanceObserver.observe 函式,它接受兩個引數entryTypesbuffered

  • entryTypes 宣告需要觀察哪幾類效能資料
  • buffered 宣告回撥函式是立即同步執行還是非同步執行,例子如下
const {
  performance,
  PerformanceObserver
} = require('perf_hooks');

const obs = new PerformanceObserver((list, observer) => {
  // 同步執行三次. 每次`list` 僅包含一項 item.
});
obs.observe({ entryTypes: ['mark'] });

for (let n = 0; n < 3; n++)
  performance.mark(`test${n}`);
複製程式碼
const {
  performance,
  PerformanceObserver
} = require('perf_hooks');

const obs = new PerformanceObserver((list, observer) => {
  // 執行一次. `list` 包含3個 items.
});
obs.observe({ entryTypes: ['mark'], buffered: true });

for (let n = 0; n < 3; n++)
  performance.mark(`test${n}`);
複製程式碼

總結

Performance Timeline Level 2規範中,擴充了performance的定義,並增加了PerformanceObserver的支援。

相比PerformanceObserverwindow.performance在瀏覽器中相容性較好,另外Performance Hooks在 Node.js 中仍然處於 Experimental 階段。

推薦在瀏覽器相容的情況下使用PerformanceObserver,使用這種觀察者模式可以解決主動呼叫的問題,而且更為優雅。

相關文章