H5性能分析及前端性能監控:window.performance


window.performance 是W3C性能小組引入的新的API,目前IE9以上的瀏覽器都支持。一個performance對象的完整結構如下圖所示:

memory字段代表JavaScript對內存的占用。

navigation字段統計的是一些網頁導航相關的數據:

  1. redirectCount:重定向的數量(只讀),但是這個接口有同源策略限制,即僅能檢測同源的重定向;
  2. type 返回值應該是0,1,2 中的一個。分別對應三個枚舉值:
    • 0 : TYPE_NAVIGATE (用戶通過常規導航方式訪問頁面,比如點一個鏈接,或者一般的get方式)
    • 1 : TYPE_RELOAD (用戶通過刷新,包括JS調用刷新接口等方式訪問頁面)
    • 2 : TYPE_BACK_FORWARD (用戶通過后退按鈕訪問本頁面)

最重要的是timing字段的統計數據,它包含了網絡、解析等一系列的時間數據。

2.2.1 timing API

timing的整體結構如下圖所示:

各字段的含義如下:

startTime:有些瀏覽器實現為navigationStart,代表瀏覽器開始unload前一個頁面文檔的開始時間節點。比如我們當前正在瀏覽baidu.com,在地址欄輸入google.com並回車,瀏覽器的執行動作依次為:unload當前文檔(即baidu.com)->請求下一文檔(即google.com)。navigationStart的值便是觸發unload當前文檔的時間節點。

如果當前文檔為空,則navigationStart的值等於fetchStart。

redirectStart和redirectEnd:如果頁面是由redirect而來,則redirectStart和redirectEnd分別代表redirect開始和結束的時間節點;
unloadEventStart和unloadEventEnd:如果前一個文檔和請求的文檔是同一個域的,則unloadEventStart和unloadEventEnd分別代表瀏覽器unload前一個文檔的開始和結束時間節點。否則兩者都等於0;
fetchStart是指在瀏覽器發起任何請求之前的時間值。在fetchStart和domainLookupStart之間,瀏覽器會檢查當前文檔的緩存;
domainLookupStart和domainLookupEnd分別代表DNS查詢的開始和結束時間節點。如果瀏覽器沒有進行DNS查詢(比如使用了cache),則兩者的值都等於fetchStart;
connectStart和connectEnd分別代表TCP建立連接和連接成功的時間節點。如果瀏覽器沒有進行TCP連接(比如使用持久化連接webscoket),則兩者都等於domainLookupEnd;
secureConnectionStart:可選。如果頁面使用HTTPS,它的值是安全連接握手之前的時刻。如果該屬性不可用,則返回undefined。如果該屬性可用,但沒有使用HTTPS,則返回0;
requestStart代表瀏覽器發起請求的時間節點,請求的方式可以是請求服務器、緩存、本地資源等;
responseStart和responseEnd分別代表瀏覽器收到從服務器端(或緩存、本地資源)響應回的第一個字節和最后一個字節數據的時刻;
domLoading代表瀏覽器開始解析html文檔的時間節點。我們知道IE瀏覽器下的document有readyState屬性,domLoading的值就等於readyState改變為loading的時間節點;
domInteractive代表瀏覽器解析html文檔的狀態為interactive時的時間節點。domInteractive並非DOMReady,它早於DOMReady觸發,代表html文檔解析完畢(即dom tree創建完成)但是內嵌資源(比如外鏈css、js等)還未加載的時間點;
domContentLoadedEventStart:代表DOMContentLoaded事件觸發的時間節點:

頁面文檔完全加載並解析完畢之后,會觸發DOMContentLoaded事件,HTML文檔不會等待樣式文件,圖片文件,子框架頁面的加載(load事件可以用來檢測HTML頁面是否完全加載完畢(fully-loaded))。

domContentLoadedEventEnd:代表DOMContentLoaded事件完成的時間節點,此刻用戶可以對頁面進行操作,也就是jQuery中的domready時間;
domComplete:html文檔完全解析完畢的時間節點;
loadEventStart和loadEventEnd分別代表onload事件觸發和結束的時間節點

2.2.2 計算性能指標

可以使用Navigation.timing 統計到的時間數據來計算一些頁面性能指標,比如DNS查詢耗時、白屏時間、domready等等。如下:

  • DNS查詢耗時 = domainLookupEnd - domainLookupStart
  • TCP鏈接耗時 = connectEnd - connectStart
  • request請求耗時 = responseEnd - responseStart
  • 解析dom樹耗時 = domComplete - domInteractive
  • 白屏時間 = domloadng - fetchStart
  • domready時間 = domContentLoadedEventEnd - fetchStart
  • onload時間 = loadEventEnd - fetchStart

2.2.3 Resource timing API

Resource timing API是用來統計靜態資源相關的時間信息,詳細的內容請參考W3C Resource timing。這里我們只介紹performance.getEntries方法,它可以獲取頁面中每個靜態資源的請求,【以百度移動版首頁的logo為例】如下:

 


可以看到performance.getEntries返回一個數組,數組的每個元素代表對應的靜態資源的信息,比如上圖展示的第一個元素對應的資源類型initiatorType是圖片img,請求花費的時間就是duration的值。

關於Resource timing API的使用場景,感興趣的同學可以深入研究。

(function() {

    handleAddListener('load', getTiming)

    function handleAddListener(type, fn) {
        if(window.addEventListener) {
            window.addEventListener(type, fn)
        } else {
            window.attachEvent('on' + type, fn)
        }
    }

    function getTiming() {
        try {
            var time = performance.timing;
            var timingObj = {};

            var loadTime = (time.loadEventEnd - time.loadEventStart) / 1000;

            if(loadTime < 0) {
                setTimeout(function() {
                    getTiming();
                }, 200);
                return;
            }

            timingObj['重定向時間'] = (time.redirectEnd - time.redirectStart) / 1000;
            timingObj['DNS解析時間'] = (time.domainLookupEnd - time.domainLookupStart) / 1000;
            timingObj['TCP完成握手時間'] = (time.connectEnd - time.connectStart) / 1000;
            timingObj['HTTP請求響應完成時間'] = (time.responseEnd - time.requestStart) / 1000;
            timingObj['DOM開始加載前所花費時間'] = (time.responseEnd - time.navigationStart) / 1000;
            timingObj['DOM加載完成時間'] = (time.domComplete - time.domLoading) / 1000;
            timingObj['DOM結構解析完成時間'] = (time.domInteractive - time.domLoading) / 1000;
            timingObj['腳本加載時間'] = (time.domContentLoadedEventEnd - time.domContentLoadedEventStart) / 1000;
            timingObj['onload事件時間'] = (time.loadEventEnd - time.loadEventStart) / 1000;
            timingObj['頁面完全加載時間'] = (timingObj['重定向時間'] + timingObj['DNS解析時間'] + timingObj['TCP完成握手時間'] + timingObj['HTTP請求響應完成時間'] + timingObj['DOM結構解析完成時間'] + timingObj['DOM加載完成時間']);

            for(item in timingObj) {
                console.log(item + ":" + timingObj[item] + '毫秒(ms)');
            }

            console.log(performance.timing);

        } catch(e) {
            console.log(timingObj)
            console.log(performance.timing);
        }
    }
}
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM