User Time API

瞭解網頁應用程式

Alex Danilo

高效能網頁應用程式是提供良好使用者體驗的關鍵。隨著網路應用程式變得越來越複雜,瞭解效能對產生的影響將是打造引人入勝體驗的關鍵。過去幾年來,瀏覽器中出現了許多不同 API,可協助分析網路效能、載入時間等。但這些 API 不一定能提供足夠精細的詳細資料,也不一定能找出拖慢應用程式的運作速度。輸入 User Timing API,這個 API 可讓您檢測網頁應用程式,找出應用程式花費時間的部分。本文將說明 API 和相關使用範例。

無法評估無法評估的項目

加快緩慢網頁應用程式的第一步,就是設法找出使用者花在哪些地方。想要找出熱門位置,評估 JavaScript 程式碼區域的時間效果是最佳方式,這是找出改善成效的第一步。幸運的是,User Timing API 可讓您在 JavaScript 的不同部分插入 API 呼叫,然後擷取詳細的時間資料,以便進行最佳化。

高解析度時間且now()

精確的時間測量是準確的要素。過去,我們的時間約是以毫秒為單位的測量時間,但建立無需卡頓的 60 FPS 網站,則每個影格都必須在 16 毫秒內繪製完成。因此,如果您只有毫秒的準確率,就無法獲得良好分析所需的精確度。輸入「High Resolution Time」,這是新式瀏覽器內建的新的時間類型。「高解析度時間」可提供浮點時間戳記,準確解析為微秒解析度,比過去幾千倍,

如要在網頁應用程式中查看目前時間,請呼叫 now() 方法,形成「效能」介面的「擴充功能」。以下程式碼說明如何執行這項作業:

var myTime = window.performance.now();

還有另一個名為「PerformanceTiming」PerformanceTiming的介面,這個介面可以列出多個與網頁應用程式載入方式相關的時間。now() 方法會傳回 PerformanceTiming 中的 navigationStart 時間經過的時間。

DOMHighResTimeStamp 類型

嘗試過去的網頁應用程式時,您需要使用類似 Date.now() 的項目,以傳回 DOMTimeStamp。DOMTimeStamp 傳回整數 (毫秒) 做為其值。為了提升高解析度時間所需的準確度,導入了名為 DOMHighResTimeStamp 的新型類型。此型別是浮點值,也會傳回時間 (以毫秒為單位)。不過,由於這是浮點,此值可以代表分數的毫秒,因此能產生一千毫秒的準確率。

使用者載入時間介面

現在,我們已取得高解析度的時間戳記,接著要使用「使用者載入時間」介面擷取時間資訊,

有了「使用者載入時間」介面,我們就能在應用程式中的不同位置呼叫方法,藉此提供 Hansel 和 Gretel 樣式的導覽標記追蹤記錄,方便我們追蹤時間花在哪些地方。

使用了 mark()

mark() 是時間分析工具包的主要工具。mark() 的作用是儲存時間戳記。mark() 的好處是可以命名時間戳記,API 會將名稱和時間戳記儲存為單一單位。

在應用程式的不同位置呼叫 mark(),您可以計算在網頁應用程式中使用該「標記」花費的時間。

規格提出多個建議名稱,讓標記可能有趣且容易解釋,例如 mark_fully_loadedmark_fully_visiblemark_above_the_fold 等。

例如,我們可以使用下列程式碼,設定應用程式完全載入時的標記:

window.performance.mark('mark_fully_loaded');

只要在整個 Web 應用程式中設定具名標記,我們就能在心中收集完整的時間資料並加以分析,藉此瞭解應用程式的發展和運作時間。

使用 measure() 計算測量結果

設好多個時間標記後,你必須找出兩者之間的經過時間。您可以使用 measure() 方法執行此操作。

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

例如,您可以使用類似這樣的程式碼,從 DOM 完成到應用程式狀態完全載入完畢的時間:

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

呼叫 measure() 時,系統會儲存結果 (不受您設定的標記影響),方便您日後擷取。透過保留應用程式執行時的作業時間,應用程式會持續回應,而您可以在應用程式完成一些工作之後,將所有資料轉儲出去供日後分析。

正在捨棄含有 clearMarks() 的標記

有時候,您可以刪掉已經設定好的許多標記。例如,您可以在網頁應用程式上進行批次執行,因此想要在每次執行時重新開始。

使用 clearMarks() 即可輕鬆移除事先設定的標記。

因此,以下程式碼範例會捨棄所有現有的標記,以便您在需要時重新設定執行時間。

window.performance.clearMarks();

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

window.peformance.clearMarks('mark_fully_loaded');

會移除我們第一個範例設定的標記,並保留我們設定的其他標記。

您可能也想移除您已採取的任何措施,而有對應的方法稱為 clearMeasures()。運作方式與 clearMarks() 相同,但您可以使用任何您執行的測量。例如,程式碼如下:

window.performance.clearMeasures('measure_load_from_dom');

我們將移除在上述 measure() 範例中執行的測量指標。如要移除所有測量指標,此做法的運作方式與 clearMarks() 相同,只要呼叫不含引數的 clearMeasures() 即可。

取得時間資料

設定標記和測量間隔都是件好事,但有時您可能會想要掌握該時間的資料來進行一些分析。這項操作也很簡單,只要使用 PerformanceTimeline 介面即可。

舉例來說,getEntriesByType() 方法可讓我們取得所有標記時間,或將所有的測量時間顯示為清單,以便我們疊代並擷取資料。更棒的是,這份清單會按照時間先後順序傳回,因此您可以使用標記在 Web 應用程式中的順序查看。

程式碼如下:

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

會傳回 Web 應用程式中所有已命中的所有標記清單,同時傳回程式碼:

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

會傳回我們採取的所有措施清單。

您也可以使用您指定的名稱來傳回項目清單。例如,以下程式碼:

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

會傳回包含 startTime 屬性中「mark_full_載入」時間戳記的清單。

計時 XHR 要求 (範例)

現在,掌握了 User Timing 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,然後告訴您如何加快應用程式執行速度,使用者也會感謝您提升使用體驗。