Resource Timing API提供了讓用戶查看一個資源從輸入url到下載下來經歷的各個過程所消耗的時間,藉此能夠來衡量網站的性能。 咱們能夠經過Resource Timing Api監控哪一個階段消耗時間比較長,而後針對該階段進行優化,好比發現一個請求的過程當中服務器返回時間過長,則須要對服務器進行優化了。css
瀏覽器從請求資源到資源下載下來,會通過多個階段,一個請求生命週期的主要階段包括:html
咱們能夠藉助chrome的devtools查看,在network選項卡下,點擊某個請求,選中Timing就能夠看到devtools給咱們提供的關於timing resource各個階段的詳細時間了。 web
Queueing: 請求被阻塞,放入等待隊列中等待。
通常如下幾個緣由會被阻塞:chrome
一、若是這個資源加載優先級比較低,好比圖片(html/css/js的優先級比圖片高),那麼圖片請求就會被渲染引擎阻塞,等待優先級高的資源加載完成才從隊列中取出,等待發送。
二、咱們知道瀏覽器對同一域名下對TCP鏈接的併發數有限制(防止資源被消耗殆盡),chrome這邊是6,那麼若是同一域名下請求多於6的話,後面的請求就會被阻塞。
三、等待釋放TCP鏈接瀏覽器
Stalled: 等待發送所用的時間,緣由同上。緩存
DNS Lookup:DNS查詢時間bash
Initail connection:創建TCP鏈接所用的時間服務器
SSL:創建SSL鏈接所用的時間網絡
Request sent:發出請求的時間,一般不到一毫秒併發
TTFB:第一字節時間,即請求發出到接受到服務器第一個字節的時間,若是這個時間太長,通常有兩個緣由:
一、網絡太差
二、服務器響應太慢
通常建議不要這個階段的時間不要超過200毫秒。
Content Download:資源下載時間,若是被阻塞,則這個時間會很長,或者資源過大也會致使下載時間過長。例如js執行時間過長,那麼圖片加載下來的時間就會被拉到很長。
現代瀏覽器提供了Api讓用戶能夠查看圖1各個階段所消耗的時間,以便用戶用Api獲取資源加載過程當中的具體狀況,排查耗時的階段,而後進行對應的優化。
經過window.performance.getEntriesByType('resource')獲取全部的PerformanceResourceTiming:
if('performance' in window) {
// 獲取的是全部的PerformanceResourceTiming
var resources = window.performance.getEntriesByType('resource')
// 遍歷各個資源加載的時間
resources.map((resource) => {
// 這裏以圖片爲例,判斷圖片加載的時間
if(resource.initiatorType === 'img') {
// duration取的是整個過程當中經歷的時間,即圖1的startTime到responseEnd直接的時間,即等於resource.responseEnd - resource.startTime
if(resource.duration > 5000) {
// 圖片加載超過了5秒了,上報服務器,提示圖片加載過長
reportToServer()
}
}
})
}
複製代碼
注意,上面的代碼須要在onload事件上面執行(onload會在圖片加載完畢之後調用)。
PerformanceResourceTimeing包含如下的屬性:
下面的屬性是以毫秒爲單位,對應圖1
因此咱們得出這樣的一個計算:
查看DNS查詢時間: domainLookupEnd - domainLookupStart
查看TCP三次握手時間: connectEnd - connectStart
request請求時間: responseEnd - responseStart
整個過程時間: responseEnd - startTime 或者 duration
一、根據HTML構建DOM樹
二、根據css構建CSSOM規則樹
三、根據DOM樹和CSSOM樹渲染合併渲染樹
四、根據渲染樹計算元素的位置和大小
五、將元素顯示在屏幕上
在此過程當中,解析到script會阻塞dom的解析和渲染(但其餘資源的下載仍是並行下載的)。執行完js後又會從新構建DOM樹和CSSOM樹,再構建渲染樹,如此反覆。
css被視爲阻塞渲染的資源,不會阻塞dom的解析,但會阻塞dom的渲染。瀏覽器爲了不dom渲染完後,css樣加載完再去渲染一次,就會阻塞dom的渲染。否則會有兩次渲染,從性能上和用戶體驗上都很差。
若是把加載css放在body後,瀏覽器爲了防止上面的情況的發生,會等待css加載完纔去渲染dom,這樣就會白屏了,因此建議css放在head裏去加載。
因此,css放在head加載是一個很好的優化。
js即會阻塞dom的解析,也會阻塞dom的渲染。js是單線程的,在執行js的時候,瀏覽器會將控制權交給js,dom解析和渲染都會阻塞。
若是把js加載放在頭部,那麼dom的解析和渲染就中止了,這樣會致使兩個問題:
一、一方面,若是這時候js要獲取dom或者操做dom都會報錯。
二、另外一方面,用戶等待頁面展現出來的時間也會加長,因此建議js加載放在底部。
備註:若是都放在head中,css在前,js在後,則瀏覽器爲了讓js獲取到的樣式是準確的,則會在css加載完前阻塞js的執行。若是把js寫在前,css在後,瀏覽器會預加載css,這樣的效果會比css在前阻塞後面的js執行好。
咱們能夠將script的加載設爲異步加載,即defer/async,這樣它就不會阻塞dom的解析和渲染。
結合以上,咱們建議把css的引入放在head,把js的引入放在body以後,若是js能夠異步加載,咱們可使用異步加載的方式。多說一句,現代瀏覽器有freload和frefetch的預加載,也能夠提升頁面加載速度,有興趣的能夠去查閱下資料。
圖片的加載不會阻塞dom的渲染,試想下,若是圖片加載會阻塞dom的渲染的話,那麼在多圖的網站(如今很常見),等待圖片所有加載出來纔去渲染dom,那麼用戶體驗將會是特別的差,因此圖片的加載順序優先級是比較低的。
參考連接:
developers.google.com/web/tools/c…
developers.google.com/web/fundame… juejin.im/post/59c606…
juejin.im/entry/59e1d…