html5 performance 的應用嘗試.

來源:互聯網
上載者:User
var namespace = {};void function (window, document,  ns, undefined){        ns = window[ns];        if(!window.performance || ns.Performance){    //performance api , (Date : 2011-11),  ie9+(包括相容模式), chrome11+, Firefox7+ . (Safari,Opera. 沒有實現)         return;    }            var mixin = function (oTarget ,oSource) {            var s;            for (s in oSource){                if(oSource.hasOwnProperty(s)){                    oTarget[s] = oSource[s];                }            }            return oTarget;        },        performance = window.performance,        timing = performance.timing,        navigation = performance.navigation,        create = function (properties) {            var obj;                        if(Object.create){                return Object.create(null, properties);            }                                    obj = {};            for (var s  in properties){                /*                                    ie9+ 相容模式. performance 可用,但ES5 相關特性不可用.                    但是getter 的設計,本來是為瞭解決.擷取時間不正確的狀況處理的.                    比如 responseTime 的設計.  為瞭解決這個問題.引入了update介面.                                */                if(properties.hasOwnProperty(s)){                    if(typeof properties[s].get == 'function'){                        //如果屬性是一個函數,那麼就應該是需要延遲擷取的屬性.則調用相關get方法擷取當前值.                        obj[s] = properties[s].get();                    }else{                        obj[s] = properties[s].value;                    }                }            }            return obj;         },        properties = {            isDirectClientCache : {//是否直接走的用戶端緩衝.                value : function () {                    if(navigation.type === 1){//重新整理的訪問,自然不可能直接走cache.                        return false;                    }                    if(timing.requestStart === 0){//Firefox7,當直接走緩衝時request,connect相關時間節點都為0                        return true;                    }                    if(timing.connectStart === timing.connectEnd){//Freifox8+,Chrome11+,IE9+                    //應注意的是,有時候304時, 如果資源問本地檔案,chrome會因為connect串連建立過快,而導致 此處為true. 但基本線上應不會出現此類問題.                    //另一個解決思路是對比responseStart和responseEnd.但這個受幹擾影響更多.更不靠譜.                        return true;                    }                                        return false;                }()            },            navigationType : {                value : navigation.type                 /*                      0  nomal get or link .                      1  reload.                       2 back forward.                    3 reserved . (oters method.)                    但應注意的是,Firefox8+,開始又恢複了Firefox3.5-的老問題,即返回(後退)的方式訪問頁面,onload不會被觸發.                    所以如果搜集資訊上報,是在onload回調中,就要警惕,Firefox8+瀏覽器,會導致上報指令碼,沒有被執行的問題.                    Opera,Safari 也存在同樣的問題,將來這兩款瀏覽器支援performance時也應注意.                    另外一個問題就是,domContentLoaded事件存在onload同樣的問題.只有IE和Chrome,沒有這個問題.                    最靠譜的做法是註冊到onpageshow上(如果瀏覽器支援的話). 否則.除非我們犧牲精準度.來直接執行指令碼...                                                            輔onpageshow 事件支援情況:                                            onpageshow的支援列表:                        Firefox 1.5 +                        Safari5+                        Chrome4+                        Opera12,IE10 PP2,至今仍未支援 .                                    */            },            redirectCount : {//只能統計到同源的重新導向次數.                value : navigation.redirectCount            },            redirectTime : {//重新導向消耗的時間.                value : timing.redirectEnd - timing.redirectStart            },            /* fetchTime,我們 拿到,沒什麼價值,也沒有最佳化的可能性存在.            fetchTime : {                value : Math.max(timing.domainLookupStart - timing.fetchStart, 0)                //Firefox的domainLookupStart,如果因沒有發生dns look up ,則該值不是fetchStart,而是navigationStart的值.並沒有遵守標準.            },            */            domainLookupTime : {                value : timing.domainLookupEnd - timing.domainLookupStart            },            connectTime : {//注意,這個不是串連保持的時間,而是與伺服器端建立串連所花費的時間.                value : timing.connectEnd - timing.connectStart            },            requestTime : {//因為木有準確的擷取RequestEnd的有效辦法.所以這個值實際上是我們接收到伺服器響應資料的那個時間 減去發出HTTP請求,所花費的時間.                //注意,Firefox 7,在走cache時.requestStart,會為0.Firefox8以修複.當無法正確擷取時,我們應該返回 -1.                value : timing.responseStart - (timing.requestStart || timing.responseStart + 1)            }        },        deferrProperites = {                //延時的屬性            responseTime : {                /*                                    .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的情況下.).會根據每次接收到的資料區塊的時間,去更新.responseEnd的時間.                         Chrome17-,Firefox7,則在分段資料的接受過程中,不會更新.responseEnd的時間,其值,始終為0.                                            基於不確定性,所以該值被擷取的時如果過早,就返回 -1, 否則返回正確的值.                    DomContentLoaded., 即語義上的DOM Parse 也早已結束了.而且其他資源也都加在完畢了.   而更早的 domInteractive .IE系列存在bug:                    IE9 - IE10 PP2(IE10,走cache情況除外). 在分段輸出文檔的情況下,該值並不是全部文檔解析完成後的時間,而是第一個資料區塊被解析完成的時間.                         實現差異:(由於草案中,並未提及,文檔解析並未結束時,其預設值的應該是多少.導致瀏覽器實現有差異.)                        按我個人理解,並未解析結束,應該為0. 但是IE似乎對這個東西理解不太一樣. 其他瀏覽器會是0.                         但是. IE9-IE10 PP2,則會比較有趣.即使是分段輸出,我取到的值.也和onload以後去到的,domInteractive的值是一致的.                          導致這一神奇現象的原因是,正式IE系的bug所導. 該時間是錯誤的引用了,DOM解析完成第一個資料區塊的時間.而不是整個文檔的.                         但是糾結起來就要挖掘更深層次的原因了. 因為草案只說該值體現的是,使用者代理程式把"current document readiness" 設定為 "interactive"的時間.                        如果IE系處理分段輸出的html文檔,向來都是這樣做的。那麼該值與其他瀏覽器的差異。也是可以理解的.                                         基於,以上綜合原因,所以決定藉助domContentLoadedEventStart 檢測來確定responseTime是否可信. 如不可信,則返回-1.                                */                get : function () {//此值IE9僅共參考.並不值信任.IE10則可信任.                    var val = timing.responseEnd - timing.responseStart;                    if(timing.domContentLoadedEventStart){                        if(val < 0 ) {//修正chrome16- 走cache時的bug.                            val = 0;                        }                    }else {                        val = -1;                    }                    return val;                }                            },            domParsingTime : {//IE系不可信任.職能期待IE系將來的實現了.                get : function () {                    /*                        注意IE9 - IE10 PP2,bug.  IE下,這個計算出來的值,僅共參考.完全不靠譜.                        iE9 - IE10 PP2 , 當文檔是chunked方式輸出的時候.總是要等最後一個chunked被瀏覽器接收後,                        domLoading才會有有效值.  也就是說,IE中目前的狀況是.domLoading.無論如何,都要晚於responseEnd.                        其他瀏覽器則無此問題.  但是這個問題導致我們計算IE下DOM Parsing等後續的一系列時間不準確.                         即 domInteractive - domLoading 甚至會經常得到0.                                                                                                                   */                                                          return timing.domContentLoadedEventStart ? timing.domInteractive - timing.domLoading : -1;                }            },            resourcesLoadedTime : {//IE系列不可信任,原因當然是分段輸出問題.domLoading不準確,導致後續計算都不準確的問題.所以僅供參考.                /*                   此時間指的是.頁面所有onload計算範圍內的資源載入結束後到文檔開始進行dom parse的時間段.                                 */                get : function () {                    return timing.loadEventStart ? timing.loadEventStart - timing.domLoading : -1;                }            },            firstPaintTime : {//從導航到頁面首次渲染所消耗的時間.(該屬性並非標準的屬性.而是微軟私人的.目前IE9+支援)                get : function () {//如果都不支援該屬性,或,讀取該屬性時,頁面還沒有渲染,則返回 -1;                    //這段代碼是一個願望,希望將來,firstPaint 將進入草案,並被瀏覽器實現.哪怕他們依賴首碼.                    var t = timing.firstPaint ||                              timing.msFirstPaint ||                             timing.mozFirstPaint ||                             timing.webkitFirstPaint ||                             timing.oFirstPaint;                                                return t ? t - timing.fetchStart : -1;                                                                 }            },            domContentLoadedTime : {//從導航 到 頁面domReady所消耗的時間.                 get : function () {                     return timing.domContentLoadedEventStart ? timing.domContentLoadedEventStart - timing.fetchStart : -1;                }            },            windowLoadedTime :{//擷取當前文檔fetchStart 到 window.onload,所花費的總時間.                get : function () {                    return timing.loadEventStart ? timing.loadEventStart - timing.fetchStart : -1;                }            }        },        pfm = create(mixin(properties, deferrProperites));                    ns.Performance = pfm;            if(Object.defineProperty){//單體對象的方法,沒有必要掛在到prototype上. so ..        Object.defineProperty(pfm, 'update', {value : function () {return this;}});    }else{ //for IE9+,相容模式. 需要每次依賴update方法,每次都去手動更新那些不靠譜的東西.        pfm.update = function () {            for (var s in deferrProperites){                if(deferrProperites.hasOwnProperty(s)){                    pfm[s] = deferrProperites[s].get();                }            }        }    }            }(window, document, 'namespace');window.onload = function () {    setTimeout(function () {        var pfm = namespace.Performance;        pfm.update();        alert([            'isDirectClientCache : ' + pfm.isDirectClientCache,            'navigationType : ' + pfm.navigationType,            'redirectCount : ' + pfm.redirectCount,            'redirectTime : ' + pfm.redirectTime,            'domainLookupTime : ' + pfm.domainLookupTime,            'connectTime : ' + pfm.connectTime,            'requestTime : ' + pfm.requestTime,            'responseTime : ' + pfm.responseTime,            'domParsingTime : ' + pfm.domParsingTime,            'resourcesLoadedTime : ' + pfm.resourcesLoadedTime,            'firstPaintTime : ' + pfm.firstPaintTime,            'domContentLoadedTime : ' + pfm.domContentLoadedTime,            'windowLoadedTime : ' + pfm.windowLoadedTime        ].join('\n'));        }, 300);}

  

一切都在注釋裡了. 有興趣可以看看.  

 

要補充的是,這段代碼的測試環境: Chrome11+,Firefox7+,IE9+, 別的瀏覽器就沒辦法了. 另外,代碼適當使用了ES5的api . 如果不是為了這一點,那麼其實這套api應該設計成另外的樣子. 而不是屬性器.   因為我終於是被IE9的相容模式,給攪和了. 為了相容.不得不設計出update 介面出來... 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.