天天看點

html頁面性能分析,前端性能監控之performance

如果我們想要對一個網頁進行性能監控,那麼使用window.performance是一個比較好的選擇。

我們通過window.performance可以擷取到使用者通路一個頁面的每個階段的精确時間,進而對性能進行分析。

一、頁面性能監控

1、利用performance.timing來監控網頁的性能

網頁的整個生命周期

html頁面性能分析,前端性能監控之performance

PerformanceTiming屬性如下

PerformanceTiming.navigationStart

表示從同一個浏覽器上下文的上一個文檔解除安裝(unload)結束時的UNIX時間戳。如果沒有上一個文檔,這個值會和PerformanceTiming.fetchStart相同。

PerformanceTiming.unloadEventStart

表示unload事件抛出時的UNIX時間戳。如果沒有上一個文檔,或者,如果上一個文檔或所需的重定向之一不是來自同一個源, 這個值會傳回0.

PerformanceTiming.unloadEventEnd

表示unload事件處理完成時的UNIX時間戳。如果沒有上一個文檔,或者,如果上一個文檔或所需的重定向之一不是來自同一個源, 這個值會傳回0.

PerformanceTiming.redirectStart

表示第一個HTTP重定向開始時的UNIX時間戳。如果沒有重定向,或者重定向中的一個不同源,這個值會傳回0.

PerformanceTiming.redirectEnd

表示最後一個HTTP重定向完成時(也就是說是HTTP響應的最後一個比特直接被收到的時間)的UNIX時間戳。如果沒有重定向,或者重定向中的一個不同源,這個值會傳回0.

PerformanceTiming.fetchStart

表示浏覽器準備好使用HTTP請求來擷取(fetch)文檔的UNIX時間戳。這個時間點會在檢查任何應用緩存之前。

PerformanceTiming.domainLookupStart

表示域名查詢開始的UNIX時間戳。如果使用了持續連接配接(persistent connection),或者這個資訊存儲到了緩存或者本地資源上,這個值将和 PerformanceTiming.fetchStart一緻。

PerformanceTiming.domainLookupEnd

表示域名查詢結束的UNIX時間戳。如果使用了持續連接配接(persistent connection),或者這個資訊存儲到了緩存或者本地資源上,這個值将和 PerformanceTiming.fetchStart一緻。

PerformanceTiming.connectStart

傳回HTTP請求開始向伺服器發送時的Unix毫秒時間戳。如果使用持久連接配接(persistent connection),則傳回值等同于fetchStart屬性的值。

PerformanceTiming.connectEnd

傳回浏覽器與伺服器之間的連接配接建立時的Unix毫秒時間戳。如果建立的是持久連接配接,則傳回值等同于fetchStart屬性的值。連接配接建立指的是所有握手和認證過程全部結束。

PerformanceTiming.secureConnectionStart

傳回浏覽器與伺服器開始安全連結的握手時的Unix毫秒時間戳。如果目前網頁不要求安全連接配接,則傳回0。

PerformanceTiming.requestStart

傳回浏覽器向伺服器發出HTTP請求時(或開始讀取本地緩存時)的Unix毫秒時間戳。

PerformanceTiming.responseStart

傳回浏覽器從伺服器收到(或從本地緩存讀取)第一個位元組時的Unix毫秒時間戳。如果傳輸層在開始請求之後失敗并且連接配接被重開,該屬性将會被數制成新的請求的相對應的發起時間。

PerformanceTiming.responseEnd

傳回浏覽器從伺服器收到(或從本地緩存讀取,或從本地資源讀取)最後一個位元組時(如果在此之前HTTP連接配接已經關閉,則傳回關閉時)的Unix毫秒時間戳。

PerformanceTiming.domLoading

傳回目前網頁DOM結構開始解析時(即Document.readyState屬性變為“loading”、相應的 readystatechange事件觸發時)的Unix毫秒時間戳。

PerformanceTiming.domInteractive

傳回目前網頁DOM結構結束解析、開始加載内嵌資源時(即Document.readyState屬性變為“interactive”、相應的readystatechange事件觸發時)的Unix毫秒時間戳。

PerformanceTiming.domContentLoadedEventStart

傳回當解析器發送DOMContentLoaded 事件,即所有需要被執行的腳本已經被解析時的Unix毫秒時間戳。

PerformanceTiming.domContentLoadedEventEnd

傳回當所有需要立即執行的腳本已經被執行(不論執行順序)時的Unix毫秒時間戳。

PerformanceTiming.domComplete

傳回目前文檔解析完成,即Document.readyState 變為'complete'且相對應的readystatechange 被觸發時的Unix毫秒時間戳。

PerformanceTiming.loadEventStart

傳回該文檔下,load事件被發送時的Unix毫秒時間戳。如果這個事件還未被發送,它的值将會是0。

PerformanceTiming.loadEventEnd

傳回當load事件結束,即加載事件完成時的Unix毫秒時間戳。如果這個事件還未被發送,或者尚未完成,它的值将會是0

如何擷取PerformanceTiming

我們可以直接使用JS文法即可擷取到

var mytiming =window.performance.timing;

console.log(mytiming)

html頁面性能分析,前端性能監控之performance

利用timing分析網頁

DNS查詢耗時 :domainLookupEnd -domainLookupStart

TCP連結耗時 :connectEnd-connectStart

SSL安全連接配接耗時: connectEnd-secureConnectionStart

request請求耗時 :responseEnd-responseStart

解析dom樹耗時 : domComplete-domInteractive

首次渲染時間/白屏時間 :responseStart -navigationStart

domready時間:domContentLoadedEventEnd-navigationStart

onload時間(總下載下傳時間) :loadEventEnd- navigationStart

2、利用window.performance.getEntriesByType("navigation")來監控網頁的性能

window.performance.getEntriesByType("navigation")和performance.timing實際上是大同小異的,

隻是說這個window.performance.getEntriesByType("navigation")的時間更精确

如何擷取window.performance.getEntriesByType("navigation")

我們可以直接使用JS文法即可擷取到

console.log(mytiming)

html頁面性能分析,前端性能監控之performance

利用timing分析網頁

DNS查詢耗時 :domainLookupEnd -domainLookupStart

TCP連結耗時 :connectEnd-connectStart

SSL安全連接配接耗時: connectEnd-secureConnectionStart

request請求耗時 :responseEnd-responseStart

解析dom樹耗時 : domComplete-domInteractive

首次渲染時間/白屏時間 :responseStart -startTime

domready時間 :domContentLoadedEventEnd-startTime

onload時間(總下載下傳時間) :duration

二、頁面資源監控

1、頁面資源時間介紹

資源加載時間是指:網頁打開的過程中,各個圖檔、JS、CSS檔案加載的時間。

資源加載的各個階段的時間戳,如重定向、DNS查詢、TCP連接配接建立。這些階段和他們的屬性名在圖中列出。

html頁面性能分析,前端性能監控之performance

或者這麼看也行

html頁面性能分析,前端性能監控之performance

應用開發者可以使用這些屬性值去計算某個階段的耗時長度,用來幫助診斷性能問題。

我們還可以使用Chrome浏覽器的開發者模式檢視:

html頁面性能分析,前端性能監控之performance

Queueing: 請求被阻塞,放入等待隊列中等待。

一般以下幾個原因會被阻塞:

如果這個資源加載優先級比較低,比如圖檔(html/css/js的優先級比圖檔高),那麼圖檔請求就會被渲染引擎阻塞,等待優先級高的資源加載完成才從隊列中取出,等待發送。

我們知道浏覽器對同一域名下對TCP連接配接的并發數有限制(防止資源被消耗殆盡),chrome這邊是6,那麼如果同一域名下請求多于6的話,後面的請求就會被阻塞。

等待釋放TCP連接配接

Stalled: 等待發送所用的時間,原因同上。

DNS Lookup:DNS查詢時間

Initail connection:建立TCP連接配接所用的時間

SSL:建立SSL連接配接所用的時間

Request sent:送出請求的時間,通常不到一毫秒

TTFB:第一位元組時間,即請求發出到接受到伺服器第一個位元組的時間,如果這個時間太長,一般有兩個原因:

網絡太差

伺服器響應太慢

一般建議不要這個階段的時間不要超過200毫秒。

Content Download:資源下載下傳時間,如果被阻塞,則這個時間會很長,或者資源過大也會導緻下載下傳時間過長。例如js執行時間過長,那麼圖檔加載下來的時間就會被拉到很長。

2、Resource Timing API

那麼我們怎麼擷取這個資源時間呢?直接使用JS代碼調用這些公共接口即可:

var resources = window.performance.getEntriesByType('resource');

console.log(resources);

html頁面性能分析,前端性能監控之performance

startTime

在資源提取開始的時間。該值等于fetchStart。

duration

資源完成下載下傳的總時間,它是responseEnd和startTime屬性之間的差異。

redirectStart

重定向的開始時間。

redirectEnd

緊接在收到最後一次重定向響應的最後一個位元組後。

fetchStart

如果是應用緩存在實作請求,将采集 fetchStart 時間。

domainLookupStart

DNS請求開始時間

domainLookupEnd

DNS請求結束時間

connectStart

開始建立與伺服器的連接配接時間(TCP握手時間)。

connectEnd

在浏覽器完成與伺服器的連接配接以檢索資源之後(TCP握手結束時間)。

secureConnectionStart

在浏覽器啟動握手過程之前,以保護目前連接配接(如果正在使用 TLS 或 SSL 将在握手(確定連接配接安全)開始時開始)。

requestStart

浏覽器開始從伺服器請求資源之前(在對某個資源的請求被發送到伺服器後立即采集。)。

responseStart

在浏覽器收到伺服器響應的第一個位元組後(伺服器初始響應請求的時間)。

responseEnd

在浏覽器收到資源的最後一個位元組之後或緊接在傳輸連接配接關閉之前,以先到者為準(請求結束并且資料完成檢索的時間)。

transferSize

表示擷取資源的大小(以八位位元組為機關)的數字。 包括響應頭字段和響應payload body的大小。

encodedBodySize

在删除任何應用的内容編碼之前,從payload body的提取(HTTP或高速緩存)接收的大小(以八位位元組為機關)的數字。

decodedBodySize

在删除任何應用的内容編碼之後,從消息正文( message body )的提取(HTTP或緩存)接收的大小(以八位位元組為機關)的數字。

serverTiming

包含伺服器時序度量( timing metrics )的PerformanceServerTiming 條目數組。

那麼,我們可以根據這些時間屬性,對某些資源進行解析:

整個過程時間: responseEnd -startTime 或者 duration

檢視DNS查詢時間: domainLookupEnd-domainLookupStart

檢視TCP三向交握時間(HTTP): connectEnd-connectStart

SSL握手時間(HTTPS協定會有SSL握手):connectEnd-secureConnectionStart

TTFB(首包時間):responseStart-startTime

響應時間(剩餘包時間): responseEnd- responseStart

附上官方例子

各階段資源時間

functioncalculate_load_times() {//Check performance support

if (performance ===undefined) {

console.log("= Calculate Load Times: performance NOT supported");return;

}//Get a list of "resource" performance entries

var resources = performance.getEntriesByType("resource");if (resources === undefined || resources.length <= 0) {

console.log("= Calculate Load Times: there are NO `resource` performance records");return;

}

console.log("= Calculate Load Times");for (var i=0; i < resources.length; i++) {

console.log("== Resource[" + i + "] - " +resources[i].name);//Redirect time

var t = resources[i].redirectEnd -resources[i].redirectStart;

console.log("... Redirect time = " +t);//DNS time

t = resources[i].domainLookupEnd -resources[i].domainLookupStart;

console.log("... DNS lookup time = " +t);//TCP handshake time

t = resources[i].connectEnd -resources[i].connectStart;

console.log("... TCP time = " +t);//Secure connection time

t = (resources[i].secureConnectionStart > 0) ? (resources[i].connectEnd - resources[i].secureConnectionStart) : "0";

console.log("... Secure connection time = " +t);//Response time

t = resources[i].responseEnd -resources[i].responseStart;

console.log("... Response time = " +t);//Fetch until response end

t = (resources[i].fetchStart > 0) ? (resources[i].responseEnd - resources[i].fetchStart) : "0";

console.log("... Fetch until response end time = " +t);//Request start until reponse end

t = (resources[i].requestStart > 0) ? (resources[i].responseEnd - resources[i].requestStart) : "0";

console.log("... Request start until response end time = " +t);//Start until reponse end

t = (resources[i].startTime > 0) ? (resources[i].responseEnd - resources[i].startTime) : "0";

console.log("... Start until response end time = " +t);

}

}

資源大小

functiondisplay_size_data(){//Check for support of the PerformanceResourceTiming.*size properties and print their values

//if supported.

if (performance ===undefined) {

console.log("= Display Size Data: performance NOT supported");return;

}var list = performance.getEntriesByType("resource");if (list ===undefined) {

console.log("= Display Size Data: performance.getEntriesByType() is NOT supported");return;

}//For each "resource", display its *Size property values

console.log("= Display Size Data");for (var i=0; i < list.length; i++) {

console.log("== Resource[" + i + "] - " +list[i].name);if ("decodedBodySize" inlist[i])

console.log("... decodedBodySize[" + i + "] = " +list[i].decodedBodySize);elseconsole.log("... decodedBodySize[" + i + "] = NOT supported");if ("encodedBodySize" inlist[i])

console.log("... encodedBodySize[" + i + "] = " +list[i].encodedBodySize);elseconsole.log("... encodedBodySize[" + i + "] = NOT supported");if ("transferSize" inlist[i])

console.log("... transferSize[" + i + "] = " +list[i].transferSize);elseconsole.log("... transferSize[" + i + "] = NOT supported");

}

}

在W3C Web性能工作組給我們帶來的 導航計時 在2012年,它是現在市面上幾乎所有的主流浏覽器。導航計時定義了一個JavaScript API,用于測量首頁的性能。例如://導航時間

var t =performance.timing,

pageloadtime= t.loadEventStart-t.navigationStart,

dns= t.domainLookupEnd-t.domainLookupStart,

tcp= t.connectEnd-t.connectStart,

ttfb= t.responseStart-t.navigationStart;

擁有首頁的計時名額很棒,但是要診斷現實世界的性能問題,通常有必要深入研究各個資源。是以,我們擁有更新的 Resource Timing規範。該JavaScript API提供與導航計時類似的計時資訊,但為每個單獨的資源提供。一個例子是://資源計時

var r0 = performance.getEntriesByType("resource")[0]

加載時間=r0.duration,

dns= r0.domainLookupEnd-r0.domainLookupStart,

tcp= r0.connectEnd-r0.connectStart,

ttfb= r0.responseStart-r0.startTime;