本文首發於公衆號:符合預期的CoyPanjavascript
首先貼一下參考文章的地址:html
最近這段時間,我在作h5的首屏加速相關的工做。首先須要搞清楚的問題就是:首屏加速,究竟是要加速什麼? 答案可能很簡單:加快網頁的展示過程。不過再細想一下,網頁快不快是針對用戶而言的,那麼什麼樣的速度會讓用戶感到快呢?或者說,哪些指標可以衡量用戶所感知的"快"呢?web
我首先想到的衡量指標就是網頁開始請求,到頁面渲染完成展示在用戶眼前,這中間的時間差。現代瀏覽器都提供了window.performance
的api,能夠經過window.performance.timing.fetchStart
來獲取網頁開始請求時候的時間戳。頁面渲染完成的時間點,能夠在頁面的業務邏輯中判斷。我用這種打點方式統計了業務中某頁面的首屏加載時長:npm
(上圖中,橫座標是加載耗時,單位是毫秒。縱座標是各個加載耗時對應的pv數)canvas
上圖的數據中,pv總數爲90316,首屏加載時長60分位值爲:1394ms,90分位值爲:2715ms。也就是說,60%的用戶能在1394毫秒內看到完整的頁面,90%的用戶能在2715毫秒內看到完整頁面。api
在測量首屏時長的時候,爲了看到長尾數據的影響,通常會採用分位值的方式,平均數會用來做爲參考,畢竟平均數在樣本量不夠大的狀況下,受極大、極小值的影響比較大(好比我和馬雲平均年薪幾個億)。瀏覽器
上面的數據中,我只是簡單的統計了頁面總體的首屏耗時。但其實頁面加載是一個很複雜的過程。在加載過程當中,哪些指標可能會影響到用戶的體驗呢?谷歌給出瞭如下的指標:緩存
FP:首次繪製。用於標記導航以後瀏覽器在屏幕上渲染像素的時間點。這個不難理解,就是瀏覽器開始請求網頁到網頁首幀繪製的時間點。這個指標代表了網頁請求是否成功。性能
FCP:首次內容繪製。FCP 標記的是瀏覽器渲染來自 DOM 第一位內容的時間點,該內容多是文本、圖像、SVG 甚至 <canvas>
元素。
FMP:首次有效繪製。這是一個很主觀的指標。根據業務的不一樣,每個網站的有效內容都是不相同的,有效內容就是網頁中"主角元素"。對於視頻網站而言,主角元素就是視頻。對於搜索引擎而言,主角元素就是搜索框。
TTI:可交互時間。用於標記應用已進行視覺渲染並能可靠響應用戶輸入的時間點。應用可能會由於多種緣由而沒法響應用戶輸入:①頁面組件運行所需的JavaScript還沒有加載完成。②耗時較長的任務阻塞主線程
下面是參考文章中的一個例子,來直觀表示上述的四種指標。
明確了上述的幾個指標的含義後,下面介紹一下如何測量這幾個指標的值。
現代瀏覽器已經爲咱們提供了性能測試的api。直接上代碼:
PerformanceObserver
在頁面html代碼頂部加入如下代碼,訂閱性能事件。
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const metricName = entry.name;
const time = Math.round(entry.startTime + entry.duration);
console.log(entry);
console.log(metricName + ' : ' + time);
}
});
observer.observe({entryTypes: ['paint']});
複製代碼
上述代碼的輸出以下:
下面的代碼也是能夠的:
window.performance.getEntriesByType('paint');
複製代碼
FMP是一個十分主觀的指標,須要開發者本身去測量。像文章一開始說的那樣,咱們能夠在業務邏輯中判斷頁面加載、渲染完成時記錄一個時間戳,而後和window.performance.timing.fetchStart
相減,來獲得FMP。
TTI也是一個較爲主觀的指標。瀏覽器並無爲這個指標提供api。不過google提供了polyfill。下面是使用方法。
在頁面html頂部加入:
!function(){if('PerformanceLongTaskTiming' in window){var g=window.__tti={e:[]};
g.o=new PerformanceObserver(function(l){g.e=g.e.concat(l.getEntries())});
g.o.observe({entryTypes:['longtask']})}}();
複製代碼
install這個polyfill,
npm install tti-polyfill
複製代碼
在業務代碼中引用:
import ttiPolyfill from 'tti-polyfill';
...
ttiPolyfill.getFirstConsistentlyInteractive().then((tti) => {
console.log('tti', tti);
});
...
複製代碼
getFirstConsistentlyInteractive()
方法接受可選的startTime
配置選項,讓您能夠指定下限值(您知道您的應用在此以前沒法進行交互)。 默認狀況下,該 polyfill 使用 DOMContentLoaded 做爲開始時間,但一般狀況下,使用主角元素呈現的時刻或您知道全部事件偵聽器都已添加的時間點這類時間會更準確。
如何優化首屏速度?一提到這個topic,我首先想到的就是一系列寫代碼時應注意的原則,以及如下幾個點:
一、充分利用緩存。
二、資源懶加載。
三、http請求層面的優化,好比上http2。
四、若是是客戶端內的頁面,能夠作預加載等。
五、SSR。
....
本文不會深刻去討論每一種方法具體應該怎麼實施。在瞭解了文章中提到的幾個關鍵性能指標後,能夠針對頁面加載的每個階段,進行深刻的數據採集,分析和研究。在研究過程當中,天然能夠知道頁面到底慢在哪裏,不一樣的階段使用不一樣的方法進行優化。回到文章的標題,當考慮網頁首屏速度優化時,咱們在考慮什麼?其實就是在考慮經過一系列的方法,縮小網頁的FP、FCP、FMP、TTI,以給用戶提供良好的體驗。
本文根據谷歌的參考文章,對頁面加載過程當中的幾個重要時間點進行了總結,明確、細化了首屏優化的方向和思路,符合預期。