支援瀏覽器: IE9+,Chrome11+,Firefox7+.
宿主對象window.performance.
參考資料:http://msdn.microsoft.com/zh-cn/office/ff975118
參考w3c的標準草案:http://w3c-test.org/webperf/specs/NavigationTiming/
目前,IE9+和 chrome11+,Firefox7+已經實現了該草案定義的介面.
成員:
.navigation (一個叫做performanceNavigation的對象.)
.timing (這玩意是一個被稱作performanceTiming的包含了很多成員的對象)
方法:
.toJSON
返回一個 對象,並抄寫performance的可枚舉成員到其中. 是的,timing,navigation都在上面.
JSON.stringify(performance.toJSON()) == JSON.stringify(performance)//true. 悲劇啊.明明是繼承來的,msdn非要特殊標一下..
PS:
1. performance,僅能對當前的html文檔做檢測,所有的對象都和當前文檔有關. 如果我們想檢測某個圖片資源的網路狀況,則不行. 比如我們想監控,使用者訪問我們服務的狀況,就只能建立一個iframe, url為我們服務某個地址(除非使用者訪問的當前頁,就是我們要監控的對象.). 然後才可以監控這次一次請求的網路狀態等等. 所以建議如果可以考慮使用performance,做監控,則需要有 抽樣、時間點等監控機制. 否則給伺服器帶來額外壓力,得不償失. 如果要監控其他資源,需要使用 ResourceTiming. 這套api. 這個會在其他文章裡單獨說一說.
performanceNavigation(performance.navigation)對象的成員
performanceNavigation.type
傳回值應該是0,1,2 中的一個.分別對應三個枚舉值:
0 : TYPE_NAVIGATE (使用者通過常規導航方式訪問頁面,比如點一個連結,或者一般的get方式.)
1 : TYPE_RELOAD (使用者通過重新整理,包括JS調用重新整理介面等方式訪問頁面)
2 : TYPE_BACK_FORWARD (使用者通過後退按鈕訪問本頁面)
ps:草案中其實還有 3 : TYPE_RESERVED (保留,其他非前三種方式訪問.)
performanceNavigation.redirectCount
一個唯讀屬性,返回當前頁面是幾次重新導向才過來的.但是這個介面有同源策略限制,即僅能檢測同源的重新導向.
bugs:
1. IE9,當一個同源的頁面a串連到 地址b(是否於a,c同源都如此),後被重新導向到同源頁面c時.navigation.redirectCount居然會是1.而不是0,此bug已被IE10 PP2修複.
performanceTiming(performance.timing)對象的成員:
.navigationStart
瀏覽器完成卸載前一個文檔的時間(也就是準備載入新頁面的那個起始時間).如果沒有前一個文檔,那麼就返回 timing.fetchStart的值.
似乎只有Chrome 非常嚴格遵守了此草案. 即不把重新整理頁面 ,以及一個標籤頁輸入地址到指定頁面,視為發生文檔的卸載
bugs:
1. IE9,當發生重新導向時,.navigationStart 會是0. IE10 PP2 已修複此問題.
2. IE9-IE10 PP2,的一個問題是重新整理當前頁面,或在某個標籤頁輸入地址為非相同頁面時, 會被視為存在前一個文檔,也就是說,其navigationStart會早於fetchStart.(除非在當前頁再次輸入地址按斷行符號.再次進入該頁面,則被視為無前一個文檔被卸載.).而實際上這時候navigationStart,是unloadEventEnd的時間.
3. Firefox7-Firefox10,一個新標籤頁也會被視為一個有效文檔. 所以這時候,會有值,且不是fetchStart的值.
.unloadEventStart
如果前一個文檔,和當前文檔同源,返回前一個文檔發生unload事件前的時間.如果沒有前一個文檔,或不同源,則返回0.
bugs:
1. IE9-IE10 pp2,Chrome17-,在前一個文檔與當前文檔中間發生重新導向時, 且前後兩個文檔同源時, unloadEventStart,也會返回0
.unloadEventEnd
如果前一個文檔和當前文檔同源.返回前一個文檔發生unload事件的時間. 如果沒有前一個文檔,或不同源,則返回0.
如果,發生了HTTP重新導向,或者類似的事情.並且,從導航開始中間的每次重新導向,並不都和當前文檔同域的話,.則返回0
bugs:
1. IE9-IE10 pp2,Chrome17-,在前一個文檔與當前文檔中間發生重新導向時, 且前後兩個文檔同源時, unloadEventEnd,也會返回0
.redirectStart
如果,發生了HTTP重新導向,或者類似的事情.並且,從導航開始,中間的每次重新導向,都和當前文檔同域的話,就返回開始重新導向的,timing.fetchStart的值.其他情況,則返回0.
bugs:
1. IE9-IE10 pp2,在頁面a,連結到地址b,並重新導向到與b同源的頁面c時. redirectStart,將為0.即同源策略,居然會考慮導航頁.
.redirectEnd
如果,發生了HTTP重新導向,或者類似的事情.並且,從導航開始,中間的每次重新導向,都和當前文檔同域的話,就返回最後一次重新導向,接收到最後一個位元組資料後的那個時間.其他情況則返回0.
bugs:
1. IE9-IE10 pp2,在頁面a,連結到地址b,並重新導向到與b同源的頁面c時. redirectSEnd,將為0.即同源策略,居然會考慮導航頁.
.fetchStart
如果一個新的資源(這裡是指當前文檔)擷取被發起,或類似的事情發生,則 fetchStart必須返回使用者代理程式開始檢查其相關緩衝的那個時間,其他情況則返回開始擷取該資源的時間.
.domainLookupStart
返回使用者代理程式對當前文檔所屬域進行DNS查詢開始的時間. 如果此請求沒有DNS查詢過程,如長串連,資源cache,甚至是本地資源等. 那麼就返回 fetchStart的值.
bugs:
1. Firefox7-Firefox10,的實現有錯誤. 因為其值,並沒有遵守標準所描述的對應時間節點.而是預設以navigationStart作為時間起點,並以中間的重新導向時間做累加.而得到domainLookupStart的時間.即使這個重新導向是非同源的重新導向.所消耗的時間都會被計算進去. 那麼,這也就解釋了,為什麼當沒有重新導向發生時, domainLookupStart - fetchStart, 我們往往會得到一個負值的原因,因為navigationStart,是要早於 fetchStart的.
.domainLookupEnd
返回使用者代理程式對結束對當前文檔所屬域進行DNS查詢的時間.如果此請求沒有DNS查詢過程,如長串連,資源cache,甚至是本地資源等. 那麼就返回 fetchStart的值.
bugs:
1.參考domainLookupStart的bug. End具備相同的問題.
.connectStart
返回使用者代理程式向伺服器伺服器請求文檔,開始建立串連的那個時間,如果此串連是一個長串連,又或者直接從緩衝中擷取資源(即沒有與伺服器建立串連).則返回domainLookupEnd的值.
bugs:
1. Firefox7 當資源走cache,即並未建立串連時. connentStart 的值為0.
2. Firefox8-Firefox10,當並未建立串連時,connetStart的值是fetchStart的值,而不是domainLookEnd的值. 但這裡涉及到一個慣性問題,因為domainLookupEnd的累積時間就已經背離了標準了,所以即使connectStart遵守標準.也是一個有問題的值.
.connectEnd
返回使用者代理程式向伺服器伺服器請求文檔,建立串連成功後(注意,不是中斷連線的時間.)的那個時間.如果此串連是一個長串連,又或直接從緩衝中擷取資源 (即沒有與伺服器建立串連),則返回domainLookupEnd的值.
bugs:
參考connectStart的問題.connectEnd具備同樣的問題.
如果串連建立失敗,而使用者代理程式進行重連,則connectStart和connectEnd則應該是這次重連的相關的值.其中connectEnd必須包括建立串連的時間以及,SSH握手協議和SOCKS認證等時間.
.secureConnectionStart
可選特性.使用者代理程式如果沒有對應的東東,就要把這個設定為undefined.如果有這個東東,並且是HTTPS協議,那麼就要返回開始SSL握手的那個時間. 如果不是HTTPS, 那麼就返回0.
補充:Firefox7-10,IE9-IE10 PP2,都木有實現這個api.所以始終是undefined.
.requestStart
返回從伺服器、緩衝、本地資源等,開始請求文檔的時間.
如果請求中途,串連斷開了,並且使用者代理程式進行了重連,並重新請求了資源,那麼requestStart就必須為這個新請求所對應的時間.
performance.timing 並不包含一個 單表請求結束的"requestEnd"介面. 原因有兩點:
1. 使用者代理程式所能確定的請求的結束,並不能代表正確的網路栓書中的結束時間. 所以設計這個屬性並沒什麼用處.
2. 一些使用者代理程式,如果要封裝一個代表HTTP層面的,請求結束時間的介面,成本會非常高昂.
bugs: 1. Firefox7,直接走本機快取時,.requestStart的值將為0. (Firefox8已修複此問題)
.responseStart
返回使用者代理程式從伺服器、緩衝、本地資源中,接收到第一個位元組資料的時間.
.responseEnd
返回使用者代理程式接收到最後一個字元的時間,和當前串連被關閉的時間中,更早的那個. 同樣,文檔可能來自伺服器、緩衝、或本地資源.
補充: 此值的讀取應該是在我們可以確保真的是Response結束以後. 比如window.onload. 因為考慮到chunked輸出的情況. 那麼我們指令碼執行,並擷取該值時,響應還沒有結束. 這就會導致擷取時間不準確.
bugs :
1. IE10 PP2, 以及Chrome17- ,走本機快取時.在文檔中間的指令碼執行時去讀取此值, 將為0. IE9本來沒有問題,結果IE10 PP2,反倒有了問題.
2. Chrome16-,(Chrome17,已修複此問題.)在地址欄輸入相同地址,走本機快取時. responseEnd的時間,居然早於responseStart的時間. (不得不承認,這簡直就是奇葩啊!)
3. Chrome17-,從頁面a,到地址b,再重新導向到地址c, 此時如果地址c是走緩衝.則. ResponseEnd的時間,會遭遇ResponseStart的時間.(好吧,我們把希望寄予Chrome18好了.)
實現差異:(由於草案中,並未提及,當文檔被分段輸出後.在中間文檔資料,接受過程中,responseEnd應如何處理,導致瀏覽器實現存在差異.) IE9 - IE10 PP2 , Firefox8-Firefox10,在不走存在Response階段(非走cache的情況下.).以接收第一個chunked包結束的時間作為.responseEnd的時間.(這將導致後續的一系列問題.) Chrome17-,Firefox7,則在分段資料的接受過程中,不會更新.responseEnd的時間,其值,始終為0.
.domLoading
返回使用者代理程式把其文檔的 "current document readiness" 設定為 "loading"的時候.
(current document readiness 其實就是document.readyState API對應的狀態.)
參考:http://dev.w3.org/html5/spec/dom.html#current-document-readiness
bugs : 1. IE9. 在分段輸出文檔的情況下,該值總是要晚於最終responseEnd的值. 基於responseEnd的IE實現的bug.這也合情合理.
實現差異: iE9 - IE10 PP2 , 當文檔是chunked方式輸出的時候.總是要等最後一個chunked被瀏覽器接收後,domLoading才會有有效值. 也就是說,IE中目前的狀況是.domLoading.無論如何,都要晚於responseEnd.其他瀏覽器則無此問題. 但是這個問題導致我們計算IE下DOM Parse不準確. 即 domInteractive - domLoading 甚至會經常得到0.
.domInteractive
返回使用者代理程式把其文檔的 "current document readiness" 設定為 "interactive"的時候.
從標準來說,domReady的狀態為"interactive"時,意味著,文檔解析結束了. 因為標準中描述, DOM樹建立結束後第一件事,就是把 "current document readiness" 設定為"interactive"
參考:http://dev.w3.org/html5/spec/the-end.html#the-end 中第一步.
bugs : 1. IE9,IE10 PP2 . 在分段輸出文檔的情況下,該值並不是全部文檔解析完成後的時間,而是第一個資料區塊被解析完成的時間,基於responseEnd的IE實現的bug.經過向後推定這也合情合理.
實現差異:(由於草案中,並未提及,文檔解析並未結束時,其預設值的應該是多少.導致瀏覽器實現有差異.) 按我個人理解,並未解析結束,應該為0. 但是IE似乎對這個東西理解不太一樣. 其他瀏覽器會是0. 但是. IE9-IE10 PP2,則會比較有趣.即使是分段輸出,我取到的值.也和onload以後去到的,domInteractive的值是一致的. 導致這一神奇現象的原因是,正式IE系的bug所導. 該時間是錯誤的引用了,DOM解析完成第一個資料區塊的時間.而不是整個文檔的. 但是糾結起來就要挖掘更深層次的原因了. 因為草案只說該值體現的是,使用者代理程式把"current document readiness" 設定為 "interactive"的時間.如果IE系處理分段輸出的html文檔,向來都是這樣做的。那麼該值與其他瀏覽器的差異。也是可以理解的.
.domContentLoadedEventStart
返迴文檔發生 DOMContentLoaded事件的時間.
參考:http://dev.w3.org/html5/spec/the-end.html#the-end 中第4步.DOMContentLoad和 DOMInteractive 之間差了兩個步驟. 其中之一是, 所有open elements出棧 ,然後去看看 待啟動並執行script list中是否有需要啟動並執行指令碼,如果有則執行,一直到這個列表為空白了.再觸發DOMContentLoad. 需要主的是這個待運行指令碼列表.有些可能在不同瀏覽器中,被加入進去的行為可能不同. 比如 document.write寫入文檔流的指令碼,以及script deferr 的指令碼.. 所以我們應該知道deferr的指令碼也是要他延遲domContentLoaded的,也就是我們最常用的所謂domReady.(至少html5的規範是如此.)
.domContentLoadedEventEnd
文檔的DOMContentLoaded 事件的結束時間.
補充:所謂事件結束的時間,是指,如果DOMContentLoaded事件被開發人員註冊了回調事件.那麼這個時間的End時間減去Start的時間.就會是這個回調執行的大概事件. 當然居於部分瀏覽器實現可能會有2-3ms的誤差. 但是這個時間,基本可以忽略不計. 類似的情況還有後面的.loadEventStart,End. 即 window.onload 所有回調所消耗的時間.
.domComplete
返回使用者代理程式把其文檔的 "current document readiness" 設定為 "complete"的時候.
PS:如果 current document readiness 的某個狀態被多次觸發,那麼對應的 domLoading, domInteractive, domContentLoadedEventStart, domContentLoadedEventEnd and domComplete這些對應的API返回的時間,就應該是這個狀態第一次觸發的時間.
.loadEventStart
文檔觸發load事件的時間. 如果load事件沒有觸發,那麼該介面就返回0.
.loadEventEnd
文檔觸發load事件結束後的時間. 如果load事件沒有觸發,那麼該介面就返回0.
external : 另外,我很期待微軟的私人實現,msFirstPaint 的屬性。能夠得到標準的採納...這樣對於監控瀏覽器首次渲染花費的時間.有太重大的意義了。
Chrome 也有了一些私人支援:
chrome.loadTimes()
Object:
- commitLoadTime: 1340785548.955838
- finishDocumentLoadTime: 0
- finishLoadTime: 0
- firstPaintAfterLoadTime: 0
- firstPaintTime: 1340785548.973838
- navigationType: "Other"
- requestTime: 0
- startLoadTime: 0
- wasAlternateProtocolAvailable: false
- wasFetchedViaSpdy: false
- wasNpnNegotiated: false
- __proto__: Object
注意這裡有個 wasFetchedViaSpdy , 很有趣的東西 參考 : http://www.oschina.net/news/29099/what-is-spdy
有了這些東西,我們大概能做什麼呢,大家自由發揮想象吧... 一個有趣的事情是,有時候bug,未必是壞事。我們可以利用bug.可以統計到一些額外的資訊.比如:
IE,Chrome,利用 unloadEventStart,End, 以及 document.referrer .與當前文檔同源的前提下, 值為0來斷定 該兩款瀏覽器,發生了跨域的重新導向.而Firefox則可以考慮用domainLookupStart 是否大於navigationStart .以及redirectCount是否為0.來達到相同的檢測目的..
最後附上timing相關的圖,可以協助你理解這玩意的意義: