說在前面javascript
最近身體出了點問題,折騰了個把星期總算活過來。差很少個把星期沒寫博客了,今天分享一個比較好玩的東東—performancehtml
上一篇博客中分享了不少頁面性能的測試工具,一般,頁面的性能問題也是咱們開發中一個重要環節,但一直以來咱們也沒有沒有比較好的手段,來檢測頁面的性能;一般,咱們只能以來與chrome或者FF瀏覽器自帶的profile,timming或者使用在線的pagetest,阿里測等。咱們很但願有一套頁面性能的api,咱們能夠本身編寫代碼測試頁面性能而不須要藉助於其餘的工具。java
好在W3C Web性能工做小組已經git
與各瀏覽器廠商都已認識到性能對於web開發的重要性,爲了解決當前性能測試的困難,W3C推出了一套性能API標準,各類瀏覽器對這套標準的支持現在也逐漸成熟起來。這套API的目的是簡化開發者對網站性能進行精確分析與控制的過程,方便開發者採起手段提升web性能。
github
正文web
整套標準包含了10餘種API,各自針對性能檢測的某個方面。在下圖中能夠看到它們當前在規範流程中的進展:chrome
下面是API描述的功能列表
segmentfault
瀏覽器支持狀況
api
有兩個使咱們必需要關注的:數組
1. 頁面加載Navigation Timing
2. 頁面資源加載Timing: Resource Timing。
這兩個API很是有用,能夠幫助咱們獲取頁面的Domready時間、onload時間、白屏時間等,以及單個頁面資源在從發送請求到獲取到rsponse各階段的性能參數。
使用這兩個API時須要在頁面徹底加載完成以後才能使用,最簡單的辦法是在window.onload事件中讀取各類數據,由於不少值必須在頁面徹底加載以後才能得出。
(1)頁面加載Navigation Timing
該對象可以幫助網站開發者檢測真實用戶數據(RUM),例如帶寬、延遲或主頁的總體頁面加載時間。
打開chrome瀏覽器輸入:performance.timing;以下圖所示
返回了一個返回的是一個PerformanceTiming對象,包含了各類與瀏覽器性能有關的時間數據,提供瀏覽器處理網頁各個階段的耗時,它包含的頁面性能屬性以下表:
下面有一個圖,能更加直觀的展現,這些數據直接的關係。
對咱們比較有用的頁面性能數據大概包括以下幾個:
DNS查詢耗時、TCP連接耗時、request請求耗時、解析dom樹耗時、白屏時間、domready時間、onload時間等,而這些參數是經過上面的performance.timing各個屬性的差值組成的,計算方法以下:
DNS查詢耗時 :domainLookupEnd - domainLookupStart
TCP連接耗時 :connectEnd - connectStart
request請求耗時 :responseEnd - responseStart
解析dom樹耗時 : domComplete- domInteractive
白屏時間 :responseStart - navigationStart
domready時間 :domContentLoadedEventEnd - navigationStart
onload時間 :loadEventEnd - navigationStart
NavigationTiming的目的是用於分析頁面總體性能指標。若是要獲取個別資源(例如JS、圖片)的性能指標,就須要使用Resource Timing API。
Resource Timing API
這個主要用來獲取到單個靜態資源(Js,CSS,圖片,音頻視頻等等)從開始發出請求到獲取響應之間各個階段的Timing
同理在chrome的console輸入performance.getEntries();顯示了全部靜態資源的數組列表;點開後顯示了,某一個請求的相關參數有name,type,時間等等。
這個接口是獲取全部的資源;同時,該API還提供了另外另個接口
performance.getEntriesByName() performance.getEntriesByType()
顧名思義,分別是按資源的名稱和類型獲取相應的請求數據。
memory:瀏覽器內存狀況
同理輸入performance.memory
jsHeapSizeLimit
totalJSHeapSize
usedJSHeapSize
注:usedJSHeapSize表示全部被使用的js堆棧內存;totalJSHeapSize表示當前js堆棧內存總大小,這表示usedJSHeapSize不能大於totalJSHeapSize,若是大於,有可能出現了內存泄漏。
performance.navigation對象
performance還能夠提供一些用戶行爲信息,主要都存放在performance.navigation對象上面。
chrome下以下圖:
這個對象有兩個屬性:
(1)performance.navigation.type
該屬性返回一個整數值,表示網頁的加載來源,可能有如下4種狀況:
0:網頁經過點擊連接、地址欄輸入、表單提交、腳本操做等方式加載,至關於常 數performance.navigation.TYPE_NAVIGATENEXT。
1:網頁經過「從新加載」按鈕或者location.reload()方法加載,至關於常 數performance.navigation.TYPE_RELOAD。
2:網頁經過「前進」或「後退」按鈕加載,至關於常 數performance.navigation.TYPE_BACK_FORWARD。
255:任何其餘來源的加載,至關於常數performance.navigation.TYPE_UNDEFINED。
(2)performance.navigation.redirectCount
表示當前網頁通過了多少次重定向跳轉。
最後呢,本身寫了一段js來測試了上面的相關參數,代碼以下:
(function(w){ var resultObj = {}; //初始化相關 function TestTiming(timing){ var timerArr = []; var dnsTimer = {key:"DNS查詢耗時" , value:timing.domainLookupEnd - timing.domainLookupStart + "ms"}; var tcpTimer = {key:"TCP連接耗時" , value:timing.connectEnd - timing.connectStart + "ms"}; var requestTimer = {key:"request請求耗時" , value:timing.responseEnd - timing.responseStart + "ms"}; var domTimer = {key:"解析dom樹耗時" , value:timing.domComplete - timing.domInteractive + "ms"}; var pageEmptyTimer = {key:"白屏時間" , value:timing.responseStart - timing.navigationStart + "ms"}; var domReadyTimer = {key:"domready時間" , value:timing.domContentLoadedEventEnd - timing.navigationStart + "ms"}; var onloadTimer = {key:"onload時間" , value:timing.loadEventEnd - timing.navigationStart + "ms"}; timerArr = timerArr.concat(dnsTimer, tcpTimer, requestTimer, domTimer, pageEmptyTimer, domReadyTimer, onloadTimer); return timerArr; } //請求的各類資源(js,圖片,樣式等) function TestResource(resourcesObj){ var resourceArr = []; var len = resourcesObj.length; for(var i = len - 1;i >0;i--){ var temp = {}; var cur = resourcesObj[i]; temp.key = cur.name; temp.resValue = cur.responseEnd - cur.requestStart + "ms"; temp.conValue = cur.connectEnd - cur.connectStart + "ms"; resourceArr.push(temp); } return resourceArr; } //頁面的加載方式 function pageLoadMethod(type){ var arr = []; var loadMethod = {}; loadMethod.name = "進入頁面的方式"; var str = ""; switch(type){ case 0: str = '點擊連接、地址欄輸入、表單提交、腳本操做等方式加載'; break; case 1: str = '經過「從新加載」按鈕或者location.reload()方法加載'; break; case 2: str = '網頁經過「前進」或「後退」按鈕加載'; break; default: str = '任何其餘來源的加載'; break; } loadMethod.value = str; arr.push(loadMethod); return arr; } //輸出性能數據 function outPutData(perObj){ var timerArr = TestTiming(perObj.timing); var resourcesArr = TestResource(perObj.getEntries()); var loadMethodArr = pageLoadMethod(perObj.navigation.type); console.log("-------頁面初始化------------------------"); console.table(timerArr); console.log("-------頁面請求------------------------"); console.table(resourcesArr); console.log("-------頁面加載方式------------------------"); console.table(loadMethodArr); } w.perTestResult = outPutData; })(window);
說在最後
相關資料:
1 http://segmentfault.com/a/1190000004010453
2 https://github.com/fredshare/blog/issues/5
3 http://javascript.ruanyifeng.com/bom/performance.html#toc5