從一次實驗學習性能優化css
下圖是Performance 接口的屬性,提供給定頁面的與時間相關的性能信息.
html
navigation 包含了頁面瀏覽上下文的導航信息,好比大量獲取資源的重定向。web
redirectCount表示頁面加載前通過重定向次數,該接口有同源策略限制,即僅能檢測同源的重定向。ajax
返回值應該是0,1,2,255中的一個。分別對應三個枚舉值:
0 : TYPE_NAVIGATE (用戶經過常規方式訪問頁面,好比點一個連接,輸入地址等)
1 : TYPE_RELOAD (用戶經過刷新,包括JS調用刷新接口(Location.reload())等方式訪問頁面)
2 : TYPE_BACK_FORWARD (用戶經過瀏覽器歷史記錄訪問本頁面)
255: 其餘方式canvas
memory包含了堆棧使用狀況信息,usedJSHeapSize表示全部被使用的js堆棧內存;totalJSHeapSize表示當前js堆棧內存總大小,這表示usedJSHeapSize不能大於totalJSHeapSize。數組
timing包含了頁面加載時間相關的性能信息。瀏覽器
重要的參數:緩存
navigationStart:準備加載新頁面的起始時間,通常認爲是頁面最初的時間.通常和fetchStart值相等,和connectEnd中間的時間用於DNS解析,創建TCP鏈接.安全
requestStart:返回從服務器、緩存、本地資源等,開始請求文檔的時間,通常用於統計網絡資源請求的時間.性能優化
domLoading:返回當前網頁DOM結構開始解析時(即Document.readyState屬性變爲「loading」、相應的readystatechange事件觸發時)的時間,與domComplete對應,用於統計頁面渲染時間.
domComplete:返回當前網頁DOM結構生成時間,此時頁面渲染完成.
DNS查詢耗時 :domainLookupEnd - domainLookupStart
TCP連接耗時 :connectEnd - connectStart
request請求耗時 :responseEnd - responseStart
解析 DOM 樹結構的時間:domComplete - responseEnd;
通常白屏時間:responseStart - navigationStart
頁面總耗時:loadEventEnd/domComplete - navigationStart
一張timing順序圖供參考:
navigationStart:當前瀏覽器窗口的前一個網頁關閉,發生unload事件時的Unix毫秒時間戳。若是沒有前一個網頁,則等於fetchStart屬性。 unloadEventStart:若是前一個網頁與當前網頁屬於同一個域名,則返回前一個網頁的unload事件發生時的Unix毫秒時間戳。若是沒有前一個網頁,或者以前的網頁跳轉不是在同一個域名內,則返回值爲0。 unloadEventEnd:若是前一個網頁與當前網頁屬於同一個域名,則返回前一個網頁unload事件的回調函數結束時的Unix毫秒時間戳。若是沒有前一個網頁,或者以前的網頁跳轉不是在同一個域名內,則返回值爲0。 redirectStart:返回第一個HTTP跳轉開始時的Unix毫秒時間戳。若是沒有跳轉,或者不是同一個域名內部的跳轉,則返回值爲0。 redirectEnd:返回最後一個HTTP跳轉結束時(即跳轉回應的最後一個字節接受完成時)的Unix毫秒時間戳。若是沒有跳轉,或者不是同一個域名內部的跳轉,則返回值爲0。 fetchStart:返回瀏覽器準備使用HTTP請求讀取文檔時的Unix毫秒時間戳。該事件在網頁查詢本地緩存以前發生。 domainLookupStart:返回域名查詢開始時的Unix毫秒時間戳。若是使用持久鏈接,或者信息是從本地緩存獲取的,則返回值等同於fetchStart屬性的值。 domainLookupEnd:返回域名查詢結束時的Unix毫秒時間戳。若是使用持久鏈接,或者信息是從本地緩存獲取的,則返回值等同於fetchStart屬性的值。 connectStart:返回HTTP請求開始向服務器發送時的Unix毫秒時間戳。若是使用持久鏈接(persistent connection),則返回值等同於fetchStart屬性的值。 connectEnd:返回瀏覽器與服務器之間的鏈接創建時的Unix毫秒時間戳。若是創建的是持久鏈接,則返回值等同於fetchStart屬性的值。鏈接創建指的是全部握手和認證過程所有結束。 secureConnectionStart:返回瀏覽器與服務器開始安全連接的握手時的Unix毫秒時間戳。若是當前網頁不要求安全鏈接,則返回0。 requestStart:返回瀏覽器向服務器發出HTTP請求時(或開始讀取本地緩存時)的Unix毫秒時間戳。 responseStart:返回瀏覽器從服務器收到(或從本地緩存讀取)第一個字節時的Unix毫秒時間戳。 responseEnd:返回瀏覽器從服務器收到(或從本地緩存讀取)最後一個字節時(若是在此以前HTTP鏈接已經關閉,則返回關閉時)的Unix毫秒時間戳。 domLoading:返回當前網頁DOM結構開始解析時(即Document.readyState屬性變爲「loading」、相應的readystatechange事件觸發時)的Unix毫秒時間戳。 domInteractive:返回當前網頁DOM結構結束解析、開始加載內嵌資源時(即Document.readyState屬性變爲「interactive」、相應的readystatechange事件觸發時)的Unix毫秒時間戳。 domContentLoadedEventStart:返回當前網頁DOMContentLoaded事件發生時(即DOM結構解析完畢、全部腳本開始運行時)的Unix毫秒時間戳。 domContentLoadedEventEnd:返回當前網頁全部須要執行的腳本執行完成時的Unix毫秒時間戳。 domComplete:返回當前網頁DOM結構生成時(即Document.readyState屬性變爲「complete」,以及相應的readystatechange事件發生時)的Unix毫秒時間戳。 loadEventStart:返回當前網頁load事件的回調函數開始時的Unix毫秒時間戳。若是該事件尚未發生,返回0。 loadEventEnd:返回當前網頁load事件的回調函數運行結束時的Unix毫秒時間戳。若是該事件尚未發生,返回0。
performance的方法:
performance.now()返回當前網頁自從performance.timing.navigationStart到當前時間之間的微秒數(毫秒的千分之一)。精度能夠達到100萬分之一秒。利用performance.now方法,能夠獲得某種操做消耗的準確時間。
performance.mark('mark') performance.mark('markEnd') performance.measure('name', 'mark', 'markEnd') // 清除指定標記 performance.clearMarks('mark'); // 清除全部標記 performance.clearMarks();
performance.mark()用於標記某個時間點。使用該方法參數(即標記時間點),再調用 performance.measure(name, nameStart, nameEnd);便可測得某兩個時間點之間的耗時.
var start = performance.now(); // 被測代碼 var end = performance.now(); console.log('耗時:' + (end - start) + '微秒。');
performance.getEntries() 資源測速:該方法以數組形式,返回請求的時間統計信息(腳本文件、樣式表、圖片文件等等),有多少個請求,返回數組就會有多少個成員。單位是微秒(microsecond)
// 統計樣式,腳本,圖片請求數和消耗時間 var imgResource = { count: 0, time: 0 }; var cssResource = { count: 0, time: 0 }; var scriptResource = { count: 0, time: 0 }; performance.getEntries().forEach(item => { if (item.initiatorType === 'img') { imgResource.count++; imgResource.time += item.duration } else if (item.initiatorType === 'link') { cssResource.count++; cssResource.time += item.duration } else if (item.initiatorType === 'script') { scriptResource.count++; scriptResource.time += item.duration } });
Canvas基於像素,提供2D繪製函數,是一種HTML元素類型,依賴於HTML,經過腳本繪製圖形;繪製即時模式圖形,適合像素處理,動態渲染和大數據量繪製.
SVG基於矢量,提供一系列圖形元素(Rect, Path, Circle, Line …),還有完整的動畫,事件機制,能獨立使用,也能夠嵌入到HTML中.SVG 是一個保留在內存中模型中的保留模式圖形模型,而內存中模型可經過從新呈現的代碼結果進行操做,更適合用來作動態交互.
Echarts基於Canvas,而Highcharts基於SVG,本次實驗利用10萬個微博簽到數據來測試二者的性能差別.
一開始在兩個單獨文件中分別使用Echarts和Highcharts來繪製幾百個點,發現因爲網絡,引入的庫不一樣,兩者時間不具備對比性.所以轉而在同一頁面中繪製.
將全部依賴在head中引入,分別封裝兩個繪圖函數,用ajax從遠程獲取數據,在回調函數中繪圖而且統計時間,從而分析性能差別.
測試代碼:
Echarts函數
function renderEchart(weiboData) { var timeStart = window.performance.now().toFixed(4); $('.eRender span:eq(0)').html($('.eRender span:eq(0)').html() + timeStart); var myChart = echarts.init(document.getElementById('main')); myChart.setOption(option); var timeEnd = window.performance.now().toFixed(4); console.log(timeEnd - timeStart); $('.eRender span:eq(1)').html($('.eRender span:eq(1)').html() + timeEnd); $('.eRender span:eq(2)').html($('.eRender span:eq(2)').html() + (timeEnd - timeStart).toFixed(4) + 'ms'); }
Highcharts函數
function renderHchart(hda) { var timeStart = window.performance.now().toFixed(4); $('.hRender span:eq(0)').html($('.hRender span:eq(0)').html() + timeStart); var H = Highcharts, map = H.maps['cn/china'], chart; var colors = Highcharts.getOptions().colors; new Highcharts.Map('container',params) var timeEnd = window.performance.now().toFixed(4); console.log(timeEnd - timeStart); $('.hRender span:eq(1)').html($('.hRender span:eq(1)').html() + timeEnd); $('.hRender span:eq(2)').html($('.hRender span:eq(2)').html() + (timeEnd - timeStart).toFixed(4) + 'ms'); }
4.測試結果:因爲svg沒法畫出10萬個點(瀏覽器會卡死),畫3000點就須要7s.因此下面svg最多隻畫3000個點.
畫100個點:
Echarts畫10萬個點,highcharts畫3000個點:]
Echarts單獨畫10萬個點:
highcharts單獨畫3000個點:
總結:實驗結果很容易預測,canvas確定比基於dom的svg性能好得多,並且若是使用webGL,利用顯卡加速,性能會進一步提高.可是測試中遇到不少有價值的問題,例如如何利用js獲取頁面性能信息,從而作出優化策略,如何控制變量排除干擾因素使得測試更具備說服力.實驗中對performance以及面板的深刻了解也使得我對頁面整個渲染流程有了更深的認識.