User Time API

瞭解網頁應用程式

Alex Danilo

高效能的網頁應用程式是提供良好使用者體驗的關鍵。隨著網頁應用程式日益複雜,瞭解效能影響有助於打造令人信服的使用體驗。過去幾年,瀏覽器中出現了許多不同的 API,可協助分析網路效能、載入時間等,但這些 API 不一定能提供足夠彈性的細節資訊,讓您找出應用程式運作緩慢的原因。請輸入 User Timing API,這個 API 提供一種機制,可用於檢測網路應用程式耗費時間的所在位置。本文將介紹該 API 以及使用方式的範例。

您無法針對無法評估的項目進行最佳化

要加快網頁應用程式的速度,第一步就是找出耗費時間的地方。評估 JavaScript 程式碼區域的時間影響是找出熱點的最佳方法,也是找出如何改善效能的首要步驟。好消息是 User Timing API 可讓您在 JavaScript 的不同部分插入 API 呼叫,然後擷取詳細的時間資料,協助您進行最佳化。

高解析度時間和 now()

精確度是準確測量時間的基礎。過去,我們會以毫秒為單位測量時間,這沒什麼問題,但如果要打造 60 FPS 的無頓挫網站,就必須在 16 毫秒內繪製每個影格。因此,如果精確度只有毫秒,就無法進行良好分析所需的精確度。輸入 高解析度時間,這是新式瀏覽器內建的新計時類型。高解析度時間提供精準到微秒解析度的浮點時間戳記,效果比以往好上一千倍。

如要在網頁應用程式取得目前時間,請呼叫 now() 方法,建立「Performance」介面的擴充功能。以下程式碼說明如何執行這項操作:

var myTime = window.performance.now();

還有另一個稱為 PerformanceTiming 的介面,可提供與網頁應用程式載入方式相關的多個時間。now() 方法會傳回從 PerformanceTiming 發生 navigationStart 時間的經過時間。

DOMHighResTimeStamp 類型

嘗試在過去網頁應用程式的時間時,請使用 Date.now() 這類會傳回 DOMTimeStamp。DOMTimeStamp 會傳回整數毫秒值做為其值。為了盡可能提高高解析度時間所需的準確度,我們推出了名為 DOMHighResTimeStamp 的新類型。這個類型是浮點值,也會以毫秒為單位傳回時間。但由於這是浮點值,因此可以代表小數毫秒,因此精確度可達到千分之一毫秒。

使用者時間介面

既然我們已取得高解析度的時間戳記,就讓我們使用「User Timing」介面,提取時間資訊。

User Timing 介面提供的函式可讓我們在應用程式中的不同位置呼叫方法,而這些方法可提供 Hansel 和 Gretel 樣式的導覽標記記錄,讓我們追蹤時間花費的時間。

使用mark()

mark() 方法是我們的時間分析工具包中的主要工具。mark() 會為我們儲存時間戳記。mark() 的超實用之處在於,我們可以為時間戳記命名,而 API 會將名稱和時間戳記記錄為單一單位。

在應用程式的各個位置呼叫 mark(),即可計算在網頁應用程式中達到「標記」所需的時間。

規格說明書會列出一些建議的標記名稱,這些名稱可能會引起使用者興趣,且相當直觀,例如 mark_fully_loadedmark_fully_visiblemark_above_the_fold 等。

舉例來說,我們可以使用以下程式碼,為應用程式完全載入時設定標記:

window.performance.mark('mark_fully_loaded');

只要在整個網頁應用程式中設定命名標記,我們就能收集大量的時間資料,並在閒暇時進行分析,找出應用程式執行的內容和時間。

使用 measure() 計算測量值

設好多種時間標記後,您可能會想要瞭解它們之間的時間長度。您可以使用 measure() 方法執行這項操作。

measure() 方法會計算標記之間經過的時間,也可以在 PerformanceTiming 介面中,測量標記與任何已知事件名稱之間的時間。

舉例來說,您可以使用以下程式碼,計算從 DOM 完成到應用程式狀態完全載入的時間:

window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');

呼叫 measure() 時,系統會儲存結果,不受您設定的標記影響,以便您稍後擷取結果。藉由在應用程式執行期間儲存時間,應用程式仍能回應,而您可以在應用程式完成一些工作之後,轉儲所有資料,以供日後分析。

使用 clearMarks() 捨棄標記

有時候,移除已設定的標記會很有幫助。舉例來說,您可能會在網頁應用程式上執行批次作業,因此想在每次執行時重新開始。

只要呼叫 clearMarks(),即可去除您所設定的標記。

因此,下方的程式碼範例會清除您現有的所有標記,方便您視需要重新設定計時執行作業。

window.performance.clearMarks();

當然,在某些情況下,您可能不想清除所有標記。因此,如果您想移除特定標記,只要傳遞要移除的標記名稱即可。例如,下列程式碼:

window.performance.clearMarks('mark_fully_loaded');

會移除我們在第一個範例中設定的標記,但其他設定的標記則保持不變。

您可能也想移除自己建立的任何測量標準,這時可以使用對應的方法 clearMeasures()。其運作方式與 clearMarks() 完全相同,但會針對您所做的任何測量運算。例如,以下程式碼:

window.performance.clearMeasures('measure_load_from_dom');

我們將移除在上述 measure() 範例中做出的測量。如果您想移除所有措施,這項作業的運作方式與 clearMarks() 相同,也就是您只需在沒有引數的情況下呼叫 clearMeasures()

取得時間資料

設定標記和測量間隔雖然很有幫助,但您還是需要取得這些時間資料,才能進行分析。這項操作也非常簡單,只要使用 PerformanceTimeline 介面即可。

舉例來說,getEntriesByType() 方法可讓我們取得所有標記時間,或將所有測量時間列出為清單,以便我們迭代並消化資料。好消息是,系統會依時間順序傳回清單,讓您在網頁應用程式中依順序查看標記。

以下程式碼:

var items = window.performance.getEntriesByType('mark');

傳回網頁應用程式中所有已觸及的標記清單,同時程式碼:

var items = window.performance.getEntriesByType('measure');

會傳回我們建立的所有評估指標清單。

你也可以使用你為項目指定的特定名稱,取回項目清單。舉例來說,程式碼:

var items = window.performance.getEntriesByName('mark_fully_loaded');

會傳回一份清單,其中包含一個項目,其中包含的 startTime 屬性中帶有「mark_full_負載」的時間戳記。

測量 XHR 要求的時間 (範例)

瞭解 User Timing API 後,我們就能使用這個 API 分析所有 XMLHttpRequests 的網頁應用程式使用時長。

首先,我們會修改所有 send() 要求,以便發出可設定標記的函式呼叫,同時將成功回呼改為可設定其他標記的函式呼叫,然後產生要求所需的時間長度。

因此,我們的 XMLHttpRequest 通常會如下所示:

var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
  do_something(e.responseText);
}
myReq.send();

在本例中,我們會新增全域計數器來追蹤要求數量,並用於儲存每項要求的評估結果。執行此動作的程式碼如下所示:

var reqCnt = 0;

var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
  window.performance.mark('mark_end_xhr');
  reqCnt++;
  window.performance.measure('measure_xhr_' + reqCnt, 'mark_start_xhr', 'mark_end_xhr');
  do_something(e.responseText);
}
window.performance.mark('mark_start_xhr');
myReq.send();

上述程式碼會為我們傳送的每個 XMLHttpRequest 產生具有專屬名稱值的評估項目。我們假設要求會依序執行。為了處理順序錯誤的回傳要求,並行要求的程式碼需要稍微複雜一些,我們會將這部分留給讀者練習。

網頁應用程式完成一連串要求後,我們可以使用下列程式碼將所有要求轉存至主控台:

var items = window.performance.getEntriesByType('measure');
for (var i = 0; i < items.length; ++i) {
  var req = items[i];
  console.log('XHR ' + req.name + ' took ' + req.duration + 'ms');
}

結論

User Timing API 提供許多實用工具,可用於網頁應用程式的任何層面。您可以輕鬆縮小應用程式的熱點範圍,只要在整個應用程式中抽出 API 呼叫,然後再對產生的時間資料進行後續處理,就能清楚掌握時間所在。但如果您的瀏覽器不支援這個 API,該怎麼辦?沒問題,您可以在這裡找到優質的 polyfill,它能非常精確地模擬 API,並與 webpagetest.org 搭配使用。事不宜遲,立即在應用程式中試用 User Timing API,瞭解如何加快應用程式速度,讓使用者體驗更上一層樓。