1. 程式人生 > WINDOWS開發 >初探Performance API

初探Performance API

前段時間在讀Vue原始碼的時候,發現了這樣一個API——Window.Performance。當時完全不知道這是什麼?在查閱了一些資料後,大致明白了這個API的作用。下面一起來看看什麼是Performance。
其實光看這個API的名字,我們就能大致猜到這一定是和效能相關的。來看看MDN上關於它的介紹。

The Performance interface provides access to performance-related information for the current page. It‘s part of the High Resolution Time API,but is enhanced by the Performance Timeline API,the Navigation Timing API,the User Timing API,and the Resource Timing API.

Performace介面允許訪問當前頁面效能相關的資訊。它是High Resolution Time API的一部分。但是它被Performance Timeline API,and the Resource Timing API擴充套件增強了。實際上Performance的主要功能都是由這幾個API提供的。
單單看上面的內容,大家一定還是會感到疑惑,這performace究竟是個什麼東西?ok,我們直接開啟百度的網頁,然後在控制檯裡輸出Window.performance(window.performace返回的就是performance物件)

技術分享圖片

Performance物件裡出現了4個屬性。我們分別來看看這4個屬性都代表了什麼意思?

timing

timing物件提供了各種與瀏覽器處理相關的時間資料。具體如下表

名稱 作用(這裡所有時間戳都代表UNIX毫秒時間戳)
connectEnd 瀏覽器與伺服器之間的連線建立時的時間戳,連線建立指的是所有握手和認證過程全部結束
connectStart HTTP請求開始向伺服器傳送時的時間戳,如果是持久連線,則等同於fetchStart。
domComplete 當前網頁DOM結構生成時,也就是Document.readyState屬性變為“complete”,並且相應的readystatechange事件觸發時的時間戳。
domContentLoadedEventEnd 當前網頁DOMContentLoaded事件發生時,也就是DOM結構解析完畢、所有指令碼執行完成時的時間戳。
domContentLoadedEventStart 當前網頁DOMContentLoaded事件發生時,也就是DOM結構解析完畢、所有指令碼開始執行時的時間戳。
domInteractive 當前網頁DOM結構結束解析、開始載入內嵌資源時,也就是Document.readyState屬性變為“interactive”、並且相應的readystatechange事件觸發時的時間戳。
domLoading 當前網頁DOM結構開始解析時,也就是Document.readyState屬性變為“loading”、並且相應的readystatechange事件觸發時的時間戳。
domainLookupEnd 域名查詢結束時的時間戳。如果使用持久連線,或者從本地快取獲取資訊的,等同於fetchStart
domainLookupStart 域名查詢開始時的時間戳。如果使用持久連線,或者從本地快取獲取資訊的,等同於fetchStart
fetchStart 瀏覽器準備通過HTTP請求去獲取頁面的時間戳。在檢查應用快取之前發生。
loadEventEnd 當前網頁load事件的回撥函式結束時的時間戳。如果該事件還沒有發生,返回0。
loadEventStart 當前網頁load事件的回撥函式開始時的時間戳。如果該事件還沒有發生,返回0。
navigationStart 當前瀏覽器視窗的前一個網頁關閉,發生unload事件時的時間戳。如果沒有前一個網頁,就等於fetchStart
redirectEnd 最後一次重定向完成,也就是Http響應的最後一個位元組返回時的時間戳。如果沒有重定向,或者上次重定向不是同源的。則為0
redirectStart 第一次重定向開始時的時間戳,如果沒有重定向,或者上次重定向不是同源的。則為0
requestStart 瀏覽器向伺服器發出HTTP請求時(或開始讀取本地快取時)的時間戳。
responseEnd 瀏覽器從伺服器收到(或從本地快取讀取)最後一個位元組時(如果在此之前HTTP連線已經關閉,則返回關閉時)的時間戳
responseStart 瀏覽器從伺服器收到(或從本地快取讀取)第一個位元組時的時間戳。
secureConnectionStart 瀏覽器與伺服器開始安全連結的握手時的時間戳。如果當前網頁不要求安全連線,則返回0。
unloadEventEnd 如果前一個網頁與當前網頁屬於同一個域下,則表示前一個網頁的unload回撥結束時的時間戳。如果沒有前一個網頁,或者之前的網頁跳轉不是屬於同一個域內,則返回值為0。
unloadEventStart 如果前一個網頁與當前網頁屬於同一個域下,則表示前一個網頁的unload事件發生時的時間戳。如果沒有前一個網頁,或者之前的網頁跳轉不是屬於同一個域內,則返回值為0。

瞭解上面timeing提供的各種屬性之後,我們可以計算出網頁在載入時候某一部分消耗的具體時間,可以精確到千分之一毫秒。例如要計算出傳送請求到接受完資料所消耗的時間。

const timing = window.performance.timing
const contactDuration = timing.responseEnd - timing.requestStart

navagation

PerformanceNavigation介面呈現瞭如何導航到當前文件的資訊。PerformanceNavigation有兩個屬性,一個是type,表示如何導航到當前頁面的,主要有4個值。

  • type=0:表示當前頁面是通過點選連結,書籤和表單提交,或者指令碼操作,或者在url中直接輸入地址訪問的。
  • type=1: 表示當前頁面是點選重新整理或者呼叫Location.reload()方法訪問的。
  • type=2: 表示當前頁面是通過歷史記錄或者前進後退按鈕訪問的。
  • type=255: 其他方式訪問的

另外一個屬性是redirectCount,表示到達當前頁面之前經過幾次重定向。

其他屬性

performance.timeOrigin

表示performance效能測試開始的時間。是一個高精度時間戳(千分之一毫秒)

performance.onresourcetimingbufferfull

表示當瀏覽器資源時間效能緩衝區已滿時會觸發的回撥函式。下面是mdn上關於這個屬性的一個demo。這個demo的主要內容是當緩衝區內容滿時,呼叫buffer_full函式。

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 onload="init()">

performance.memory

一個非標準屬性,由chrome瀏覽器提供。這個屬性提供了一個可以獲取到基本記憶體使用情況的物件。

Performance.mark

先來看看MDN中關於mark方法的定義

The mark() method creates a timestamp in the browser‘s performance entry buffer with the given name.

這段話可以分解出三個關鍵詞。首先timestamp,這裡的timestamp指的是高精度時間戳(千分之一毫秒),其次是performance entry buffer。performance entry buffer指的是儲存performance例項物件的區域,初始值為空。最後就是given name,表示生成的每一個timestamp都有相應的名稱。
所以這句話就可以理解成,在瀏覽器的performance entry buffer中,根據名稱生成高精度時間戳。也就是很多人說過的“打點”。

Performance.measure

同樣先來看看MDN上關於measure的定義

The measure() method creates a named timestamp in the browser‘s performance entry buffer between two specified marks (known as the start mark and end mark,respectively). The named timestamp is referred to as a measure.

這段定義和上面mark的定義有些類似,其最核心的不同點在於這句話。between two specified marks。所以measure是指定兩個mark點之間的時間戳。如果說mark可以理解為"打點"的話,measure就可以理解為"連線"。

一個小例子

我們來看一個使用mark和measure的小demo,這個例子也是引用MDN,這裡做一下簡單講解。

// 標記一個開始點
performance.mark("mySetTimeout-start");

// 等待1000ms
setTimeout(function() {
  // 標記一個結束點
  performance.mark("mySetTimeout-end");

  // 標記開始點和結束點之間的時間戳
  performance.measure(
    "mySetTimeout","mySetTimeout-start","mySetTimeout-end"
  );

  // 獲取所有名稱為mySetTimeout的measures
  var measures = performance.getEntriesByName("mySetTimeout");
  var measure = measures[0];
  console.log("setTimeout milliseconds:",measure.duration)

  // 清除標記
  performance.clearMarks();
  performance.clearMeasures();
},1000);

結果如圖
技術分享圖片
可以看到,高精度的時間戳是非常精準的。(我們知道由於執行佇列的原因,setTimeout不會在給定的1000ms之後就立即執行)
Performance API提供了很多方便測試我們程式效能的介面。比如mark和measure。很多優秀的框架也用到了這個API進行測試,比如我最近在看的Vue框架。它裡面就頻繁用到了mark和measure來測試程式效能。所以想要開發高效能的web程式,瞭解Performace API還是非常重要的。

參考資料

【1】MDN Performance,Performance
【2】User Timing API
【3】performace entry buffer