前端性能優化是一個很寬泛的概念,有不少教程都有前端性能優化的方法,這也是咱們一直在關注的一件重要事情。配合各類方式、手段、輔助系統,前端優化的最終目的都是提高用戶體驗,改善頁面性能,咱們經常不遺餘力進行前端頁面優化,但卻忽略了這樣作的效果和意義。先不急於探究前端優化具體能夠怎樣去作,先看看什麼是前端性能,應該怎樣去了解和評價前端頁面的性能。前端
一般前端性能能夠認爲是用戶獲取所須要頁面數據或執行某個頁面動做的一個實時性指標,通常以用戶但願獲取數據的操做到用戶實際得到數據的時間間隔來衡量。例如用戶但願獲取數據的操做是打開某個頁面,那麼這個操做的前端性能就能夠用該用戶操做開始到屏幕展現頁面內容給用戶的這段時間間隔來評判。用戶的等待延時能夠分紅兩部分:可控 等待延時和 不可控 等待延時。可控 等待延時能夠理解爲能經過技術手段和優化來改進縮短期的部分,例如減少圖片大小讓請求加載更快、減小 HTTP 請求數等。不可控 等待延時則是不能或很難經過先後端技術手段來改進優化的,例如鼠標點擊延時、CPU 計算時間延時、ISP(Internet Service Provider,互聯網服務提供商) 網絡傳輸延時等。因此要知道的是,前端中的全部優化都是針對 可控等待延時 這部分來進行的,下面來了解一下如何獲取和評價一個頁面的具體性能。後端
獲取和衡量一個頁面的性能,主要能夠經過如下幾個方面:Performance Timing API
、Prpfile
工具、頁面埋點計時、資源加載時序圖分析。數組
Performance Timing API 是一個支持 Internet Explorer 9
以上版本及 WebKit
內核瀏覽器中用於記錄頁面加載和解析過程當中關鍵時間點的機制,它能夠詳細記錄每一個頁面資源從開始加載到解析完成這一過程當中具體操做發生的時間點,這樣根據開始和結束時間戳就能夠計算出這個過程所花的時間了。瀏覽器
圖 1-1爲 W3C標準中 Performance Timing
資源加載和解析過程記錄各個關鍵點的示意圖,瀏覽器中加載和解析一個 HTML 文件的詳細過程前後經歷 unload、redirect、App Cache、DNS、TCP、Request、Response、Processing、onload 幾個階段,每一個過程當中開始和結束的關鍵時間戳瀏覽器已經使用 performance.timing
來記錄了,因此根據這個記錄並結合簡單的計算,咱們就能夠獲得頁面中每一個過程所消耗的時間。性能優化
function performanceTest(){
let timing = performance.timing,
readyStart = timing.fetchStart - timing.navigationStart,
redirectTime = timing.redirectEnd - timing.redirectStart,
appcacheTime = timing.domainLookupStart - timing.fetchStart,
unloadEventTime = timing.unloadEventEnd - timing.unloadEventStart,
lookupDomainTime = timing.domainLookupEnd - timing.domainLookupStart,
connectTime = timing.connectEnd - timing.connectStart,
requestTime = timing.responseEnd - timing.requestStart,
initDomTreeTime = timing.domInteractive - timing.responseEnd,
domReadyTime = timing.domComplete - timing.domInteractive,
loadEventTime = timing.loadEventEnd - timing.loadEventStart,
loadTime = timing.loadEventEnd - timing.navigationStart;
console.log('準備新頁面時間耗時:'+readyStart);
console.log('redirect 重定向耗時:'+redirectTime);
console.log('Appcache 耗時'+appcacheTime);
console.log('unload 前文檔耗時:'+unloadEventTime);
console.log('DNS 查詢耗時:'+lookupDomainTime);
console.log('TCP 鏈接耗時:'+connectTime);
console.log('request 請求耗時:'+requestTime);
console.log('請求完畢至DOM加載:'+initDomTreeTime);
console.log('解析DOM樹耗時:'+domReadyTime);
console.log('Load事件耗時:'+loadEventTime);
console.log('加載時間耗時:'+loadTime);
}
複製代碼
經過上面的時間戳計算能夠獲得幾個關鍵步驟所消耗的時間,對前端有意義的幾個過程主要是解析 DOM 樹耗時、load 事件耗時和整個加載過程耗時等,不過在頁面性能獲取時咱們能夠儘可能獲取更詳細的數據信息,以供後面分析。除了資源加載解析的關鍵點計時,preformance 還提供了一些其餘方面的功能,咱們能夠根據具體須要進行選擇使用。bash
performance.memory //內存佔用的具體數據
performance.now() //performance.now()方法返回當前網頁自performance.timing到如今的時間,能夠精確到微秒,用於更加精確的計數。但實際上,目前網頁性能經過毫秒來計算就足夠了
performance.getEntries() //獲取頁面全部加載資源的performance timing 狀況。瀏覽器獲取網頁時,會對網頁中每個對象(腳本文件、樣式表、圖片文件等)發出一個HTTP請求。performance.getEntries 方法以數組形式返回全部請求的時間統計信息
performance.navigation //performance 還能夠提供用戶行爲信息,例如網絡請求的類型和重定向次數等,通常都存放在performance.navigation對象裏面
performance.navigation.redirectCount //記錄當前網頁重定向跳轉的次數
複製代碼
Performance Timing API 描述了頁面資源從加載到解析各個階段的執行關鍵點時間記錄,可是沒法統計 JavaScript 執行過程當中系統資源的佔用狀況。Profile 是 Chrome 和 Firefox 等標準瀏覽器提供的一種用於測試頁面腳本運行時系統內存和 CPU 資源佔用狀況的 API,以 Chrome 瀏覽器爲例,結合 Profile,能夠實現如下幾個功能。網絡
1.分析頁面腳本執行過程當中最耗資源的操做app
2.記錄頁面腳本執行過程當中 JavaScript 對象消耗的內存與堆棧的使用狀況dom
3.檢測頁面腳本執行過程當中 CPU 佔用狀況前端優化
使用 console.profile()
和console.profileEnd()
就能夠分析中間一段代碼執行時系統的內存或 CPU 資源的消耗狀況,而後配合瀏覽器的 Profile 查看比較消耗系統內存或 CPU 資源的操做,這樣就能夠有針對性的進行優化了。
console.profile();
//TODOS,須要測試的頁面邏輯動做
for(let i = 0; i < 100000; i ++){
console.log(i * i);
}
console.profileEnd();
複製代碼
使用Profile能夠在必定程度上幫助咱們分析頁面的性能,但缺點是不夠靈活。實際項目中,咱們不會多關注頁面的內存或CPU資源的消耗狀況,由於JavaScript有自動內存回收機制。咱們關注更多的是頁面腳本邏輯執行的時間。除了Performance Timing 的關鍵過程耗時計算,咱們還但願檢測代碼的具體解析或執行時間,這就不能寫不少的console.profile()
和console.profileEnd()
來逐段實現,爲了更加簡單地處理這種狀況,每每選擇經過腳本埋點計時的方式來統計沒部分代碼的運行時間。
頁面 JavaScript 埋點計時比較容易實現,和 Performance Timing 記錄時間戳有點相似,咱們能夠記錄 JavaScript 代碼開始執行的時間戳,後面在須要記錄的地方埋點記錄結束時的時間戳,最後經過差值來計算一段 HTML 解析或 JavaScript 解析執行的時間。爲了方便操做,能夠將某個操做開始和結束的時間戳記錄到一個數組中,而後分析數組之間的間隔就獲得每一個步驟的執行時間,下面來看一個時間點記錄和分析的例子。
let timeList = [];
function addTime(tag) {timeList.push({"tag":tag,"time":+new Date()});}
addTime("loading");
timeList.push({"tag":"load","time":+new Date()});
//TODOS,load加載時的操做
timeList.push({"tag":"load","time":+new Date()});
timeList.push({"tag":"process","time":+new Date()});
//TODOS,process處理時的操做
timeList.push({"tag":"process","time":+new Date()});
console.log(parseTime(timeList)); //輸出{load:時間毫秒數,process: 時間毫秒數}
function parseTime(time) {
let timeStep={},
endTime;
for(let i = 0,len = time.length; i < len; i ++){
if(!time[i]) continue;
endTime = {};
for(let j = i+1; j < len; j++){
if(time[j] && time[i].tag == time[j].tag){
endTime.tag = time[j].tag;
endTime.time = time[j].time;
time[j] = null;
}
}
if(endTime.time >= 0 && endTime.tag){
timeStep[endTime.tag] = endTime.time - time[i].time;
}
}
return timeStep;
}
複製代碼
這種方式經常在移動端頁面中使用,由於移動端瀏覽器 HTML 解析和 JavaScript 執行相對較慢,一般爲了性能優化,咱們須要找到頁面中執行 JavaScript 耗時的操做,若是將關鍵 JavaScript 的執行過程進行埋點計時並上報,就能夠輕鬆找出 JavaScript 執行慢的地方,並有針對性地進行優化。
咱們還能夠藉助瀏覽器或其餘工具的資源加載時序圖來幫助分析頁面資源加載過程當中的性能問題。這種方法能夠粗粒度地宏觀分析瀏覽器的全部資源文件請求耗時和文件加載順序狀況,如保證 CSS 和數據請求等關鍵資源優先加載,JavaScript 文件和頁面中非關鍵性圖片等內容延後加載。若是由於某個資源的加載十分耗時而阻塞了頁面的內容展現,那就要着重考慮。因此,咱們須要經過資源加載時序圖來輔助分析頁面上資源加載順序的問題。
圖 1-2 爲使用 Fiddler 抓取瀏覽器訪問地址時的資源加載時序圖,圖 1-3 爲 Chrome 瀏覽器訪問貓眼電影官網時的資源加載時序圖.根據資源加載時序圖咱們能夠很直觀地看到頁面上各個資源加載過程所須要的時間和前後順序,有利於找出加載過程當中比較耗時的文件資源,幫助咱們有針對性地進行優化。
圖1-2 Fiddler 頁面加載文件資源時序圖 圖1-3 Chrome瀏覽器 貓眼電影官網頁面加載文件資源時序圖經過上文介紹的利用
Performance Timing API
、Prpfile
工具、頁面埋點計時、資源加載時序圖分析幾個方面來獲取和衡量一個頁面的性能,找出加載過程當中比較耗時的文件資源,幫助咱們有針對性地進行優化。醫病必須診斷找到病因,前端性能測試在前端性能優化中屬於診斷工做,只有找到病因,才能進行鍼對性治療優化。在此歡迎你們加入QQ前端技術交流羣544587175
,在後續我會從桌面瀏覽器和移動端瀏覽器兩個方面詳細講解不一樣終端的優化策略,敬請關注......