背景

為了提供給前端者監控頁面性能的能力,W3C 定義了一系列相關 API,在這裡統稱為 Performance API。目前使用較多的應該是 PerformanceTiming,但是除了該 API,新的 W3C 草案及 WICG 提案定義了一系列 PerformanceEntry API,不僅取代了原 PerformanceTiming 的能力,並增加了更多維度的信息,本文主要針對這些 API 進行介紹。

前一篇文章中我們簡要介紹了 Performance 的能力,並用實例展示了如何使用該 API。從本篇開始,我們會更詳細的介紹 Performance 提供的一些細節能力,提供示例。希望 Performance 系列能更好的幫助開發者去優化頁面性能。

Long Task API

介紹

RAIL 模型 - Response,Animation,Idle,Load

當頁面有 task(這裡的 task 指的是內核消息循環里的一個任務)執行時間超過 50ms,內核則會通過 Long Task API 將該任務的相關信息回調給前端。把 long task 時間定義為 50ms 的主要理論依據是 Chrome 提出的 RAIL 模型,RAIL 認為事件響應應該在 100ms 以內,滾動和動畫處理應該在 16ms 以內,才能保證好的用戶體驗,而如果一個 task 執行超過 50ms,則很有可能讓體驗達不到 RAIL 的標準,故我們需要重點關注執行時間超過 50ms 的任務。

PerformanceLongTaskTiming 定義:

interface PerformanceLongTaskTiming : PerformanceEntry {
[SameObject, SaveSameObject] readonly attribute FrozenArray<TaskAttributionTiming> attribution;
};

TaskAttributionTiming 定義:

interface TaskAttributionTiming : PerformanceEntry {
readonly attribute DOMString containerType;
readonly attribute DOMString containerSrc;
readonly attribute DOMString containerId;
readonly attribute DOMString containerName;
};

TaskAttributionTiming 配合著 PerformanceLongTaskTiming 使用,記某個 long task 相關信息,具體欄位定義如下:

  • containerType: long task 來源的 frame 類型,這裡包括 "iframe" (most common), "embed", "object"
  • containerName: 包含 long task 的 element 標籤名
  • containerId: 包含 long task 的 element id
  • containerSrc: 包含 long task 的 element src 欄位的值

使用示例

var observer = new PerformanceObserver(function(list) {
var perfEntries = list.getEntries();
for (var i = 0; i < perfEntries.length; i++) {
// Process long task notifications:
// report back for analytics and monitoring
// ...
}
});

// register observer for long task notifications
observer.observe({entryTypes: ["longtask"]});

// Long script execution after this will result in queueing
// and receiving 「longtask」 entries in the observer.

當前進展

Chromium m57 代碼已經有 PerformanceLongTaskTiming 的實現,代碼在 2016-08-25 m57 分支上面首次提交,介面已經符合規範,但是具體實現不確定是否完善。從 PerformanceLongTaskTiming 對象提供的屬性來看,它提供的信息粒度還是比較粗,如果某個 JS 方法執行時間過長,並沒有信息可以直接指向該方法。

Event Timing

介紹

點擊事件是移動場景中的主要事件之一

Event Timing 是 WICG 的一個提案,主要是提供 API 來跟蹤處理時間超過 50ms 的輸入事件,這些事件類型包括:

  • MouseEvents
  • PointerEvents
  • TouchEvents
  • KeyboardEvents
  • WheelEvents
  • InputEvents
  • CompositionEvents

它提供了以下 3 個介面:

interfacePerformanceEventTiming: PerformanceEntry {// The type of event dispatched. E.g. "touchmove".// Doesnt require an event listener of this type to be registered.
readonly attribute DOMString name;// "event".
readonly attribute DOMString entryType;// The event timestamp.
readonly attribute DOMHighResTimeStamp startTime;// The time the first event handler started to execute.// |startTime| if no event handlers executed.
readonly attribute DOMHighResTimeStamp processingStart;// The time the last event handler finished executing.// |startTime| if no event handlers executed.
readonly attribute DOMHighResTimeStamp processingEnd;// The duration between |startTime| and the next time we "update the rendering // or user interface of that Document and its browsing context to reflect the // current state" in step 7.12 in the HTML event loop processing model.
readonly attribute DOMHighResTimeStamp duration;// Whether or not the event was cancelable.
readonly attribute boolean cancelable;};// Contains the number of events which have been dispatched, per event type.interfaceEventCounts{
readonly attribute unsigned long click;...
readonly attribute unsigned long touchmove;...};

partial interfacePerformance{// Contains the number of events which have been dispatched, per event type. Populated asynchronously.
readonly attribute EventCounts eventCounts;};

PerformanceEventTiming 記錄了某個事件的相關信息,具體欄位如下:

  • name:保存的是 event.type 欄位,表示一個事件的類型,例如 touchstart、touchmove
  • entryType:表示 entry 的類型,這裡是一個常量 "event"
  • startTime:保存 event.timeStamp 欄位,記錄了事件生成時的時間戳
  • processingStart:記錄內核開始處理事件的時間點
  • processingEnd:記錄內核處理完事件的時間點
  • duration:在處理完事件時,通過 Math.ceil((performance.now() - newEntry.startTime)/8) * 8 計算,這裡的處理主要是為了減少時間精度,增加安全性
  • cancelable:保存 event.cancelable 欄位,表示事件是否可以被取消
  • Performance 介面只有一個 eventCounts 屬性,它記錄了所有已經分發過的 Event,處理時間是否大於 50ms

使用示例

const performanceObserver = new PerformanceObserver((entries) => {
for (const entry of entries.getEntries()) {
console.log(entry);
}
});

performanceObserver.observe({entryTypes:[event]});

跟其他的 PerformanceEntry 一樣,都是通過 PerformanceObserver 來監聽回調。

當前進展

查看源碼,Chromium m57 還未實現 PerformanceEventTiming 相關邏輯,但是 m68 已經有 PerformanceEventTiming 對象,相關代碼在 2018-05-08 首次提交,但是跟這裡描述的並不一致,只有 processingStart 和 cancelable 2 個屬性,應該還未完善。

最新最好的內核技術文章,請搜索並關注公眾號"U4內核技術"或"u4core"。


推薦閱讀:
相关文章