前端浏览器渲染优化
By Jordan Irabor | January 17 2019
原文
介紹
我們生活在一個強(qiáng)調(diào)快速提供網(wǎng)絡(luò)服務(wù)的時代。由于web應(yīng)用的負(fù)載傳輸不斷增加,開發(fā)者必須采取最佳實(shí)踐來確保數(shù)據(jù)包被即刻分發(fā),以此提供給用戶拉稀般的網(wǎng)絡(luò)體驗
如今被web開發(fā)廣泛采用的最佳實(shí)踐是圖片壓縮、代碼壓縮、代碼打包(webpack打包)等等。這些實(shí)踐已經(jīng)被證明了能有效提高用戶體驗,如果開發(fā)者能夠深入理解瀏覽器渲染原理的話,還可以優(yōu)化性能以提高用戶體驗。
當(dāng)我們在低端機(jī)子玩對GPU要求高的游戲的時候,我們會遇到一些卡頓——環(huán)境和游戲人物的卡頓。這種現(xiàn)象(雖然不那么明顯)也會在web應(yīng)用上出現(xiàn);用戶會在進(jìn)行鼠標(biāo)點(diǎn)擊或滾動頁面等的頁面交互時感受到應(yīng)用會有一兩秒的卡頓,從而會中斷用戶的交互操作
在本文中,我們將討論Web應(yīng)用程序以每秒60幀的速度運(yùn)行(最佳)的條件
什么進(jìn)入了頁面
在web應(yīng)用上,每當(dāng)頁面發(fā)生變化,在瀏覽器內(nèi)部發(fā)生的事情是這樣的:瀏覽器為用戶提供給了一個新的頁面,以便用戶瀏覽和交互。 這些幀出現(xiàn)(并且更新)的速率以每秒幀數(shù)(fps)來度量。如果瀏覽器花了太長時間來創(chuàng)建和渲染一張頁面,fps就會下降,用戶就會感覺卡頓
為了讓瀏覽器穩(wěn)定在60幀,開發(fā)者需要理解頁面的渲染。下面是頁面創(chuàng)建的五個步驟:
瀏覽器發(fā)起get請求
服務(wù)器返回html、css
html被解析成dom
css被解析成css對象模型(cssom)并與dom整合成渲染樹
渲染樹基本上由頁面上顯示的元素組成,并構(gòu)成一個頁面。
web應(yīng)用的生命周期
在我們探索瀏覽器渲染路徑并優(yōu)化之前,我們需要學(xué)習(xí)應(yīng)用的生命周期,因為這可以使我們做出明智的選擇,以確定應(yīng)用程序何時應(yīng)該執(zhí)行“繁重的工作”。 從而創(chuàng)造流暢的用戶體驗并增強(qiáng)用戶滿意度。
應(yīng)用生命周期被分離出四個步驟:
1.Load
2.Idle
3.Animation
4.Response
Load
在用戶操作web應(yīng)用之前,web應(yīng)用就已經(jīng)被加載好了。 這是應(yīng)用生命周期的第一步并且最重要的是這一步旨在將負(fù)載時間減少(理想情況下為1s)到盡可能小的數(shù)量。
Idle
應(yīng)用加載完之后,經(jīng)常是空閑狀態(tài);等待用戶操作。應(yīng)用加載完后到用戶操作之前的這段空閑時間一般是50ms,開發(fā)者可以用這段時間坐一些耗時的工作, 例如加載一些用戶很快要用到的資源(圖片,視頻)。
專業(yè)提示:顯著減少加載時間的一個方法是首先加載UI的基礎(chǔ)節(jié)點(diǎn),然后在空閑階段引入其他元素。
Animate
當(dāng)用戶開始操作應(yīng)用并且空閑期已經(jīng)結(jié)束時,應(yīng)用程序必須對用戶交互(和輸入)做出適當(dāng)?shù)姆磻?yīng)而沒有任何明顯的延遲。
提示:研究表明,需要大約十分之一秒(在與UI元素交互之后)才注意到卡頓。 因此,在此時間范圍內(nèi)響應(yīng)用戶輸入是完美的。
當(dāng)對用戶交互的響應(yīng)涉及某種動畫時,可能會有一些挑戰(zhàn)。為了將動畫穩(wěn)定到60幀每秒,每幀的限制為16ms - 這基本上是一秒除以60。
那么,瀏覽器的開銷就應(yīng)該時10ms到12ms。 實(shí)現(xiàn)此目的的一種方法是預(yù)先執(zhí)行所有動畫計算(在UI元素與之交互后的100ms內(nèi))。
瀏覽器渲染路徑和優(yōu)化空間
瀏覽器渲染路徑有以下幾個步驟:
1.js 2.樣式計算 3.布局 4.繪制 5.合成層(Layer composition)
在網(wǎng)頁上,頁面發(fā)生改變(要么css要么js導(dǎo)致的),瀏覽器重新計算受影響元素的樣式。如果元素的位置、形狀等影響布局的地方發(fā)生更改, 瀏覽器將檢查其他元素,創(chuàng)建新布局,重新繪制受影響的元素并將這些元素重新組合在一起。
但是,更改頁面元素的某些屬性可能會更改網(wǎng)頁的渲染路徑。例如,如果是繪畫相關(guān)的屬性,比如背景圖片或者文字顏色這些有變動, 布局不會受影響因為這沒有改變屬性的位置和形狀。其他屬性更改可能會使布局生成和繪制脫離渲染管道。
我們將會展示一些關(guān)于瀏覽器渲染的一些優(yōu)化。
js
js讓開發(fā)者為用戶提供優(yōu)秀的動畫效果和視覺體驗,因此js成為web應(yīng)用中必不可少的一部分。我們在上文對應(yīng)用生命周期的討論中提到, 瀏覽器有10ms~12ms去渲染每一個頁面。為了減輕js在渲染管道的負(fù)擔(dān)(譯者:因為js執(zhí)行時間過長導(dǎo)致一頁面的渲染超過12ms), 在每個頁面(幀)中盡可能早地執(zhí)行所有JavaScript代碼非常重要,因為它可能會觸發(fā)渲染管道的其他區(qū)域。
使用 window.requesAnimationFrame() 方法很有必要,詳情請看MDN文檔
window.requestAnimationFrame()方法告訴瀏覽器您希望執(zhí)行動畫并請求瀏覽器調(diào)用指定的函數(shù)以在下一次重繪之前更新動畫。 該方法將回調(diào)作為在重繪之前調(diào)用的參數(shù)
requestAnimationFrame方法使得瀏覽器能在正確的時機(jī)引入瀏覽器并且防止掉幀。下面是一個例子:
function doAnimation() {// Some code wizardryrequestAnimationFrame(doAnimation); //schedule the next frame}requestAnimationFrame(doAnimation); 復(fù)制代碼在google開發(fā)者工具里的performance一欄中,允許開發(fā)者去記錄每一頁面(幀)繪制出來的情況,可以看到j(luò)s在web應(yīng)用中執(zhí)行的情況
雖然requestAnimationFrame方法是非常重要的工具,但是還是會有些js代碼非常耗費(fèi)資源。 網(wǎng)站在我們的操作系統(tǒng)的主線程上運(yùn)行,因此這些腳本可能會停止渲染管道的其他階段的執(zhí)行。要解決這個問題,我們可以使用Web worker。
web worker 能讓我們在新的線程執(zhí)行那些耗費(fèi)資源的js代碼。詳情請看MDN文檔
“有了web worker就簡單了,我們可以把耗時的工作丟給后臺進(jìn)程。worker進(jìn)程可以在不干擾用戶界面的情況下執(zhí)行任務(wù)。 一旦被創(chuàng)建,worker可以通過將消息發(fā)布到由該代碼指定的事件處理程序來向創(chuàng)建它的JavaScript代碼發(fā)送消息(反之亦然)。”
要使用此功能,你需要創(chuàng)建一個單獨(dú)的JavaScript文件,你的主程序?qū)⑸梢粋€Web worker。
樣式計算
樣式更改是任何Web應(yīng)用程序渲染管道的關(guān)鍵部分,因為其元素所需的樣式更改數(shù)量與樣式重新計算的性能成本成正比。 可以查看Paul’s website來了解css樣式影響渲染管道的細(xì)節(jié)。
除了樣式變更的數(shù)量,選擇器匹配應(yīng)該考慮到我們的渲染優(yōu)化列表中。選擇器匹配是指確定應(yīng)將哪些樣式應(yīng)用于任何給定DOM元素的過程。
某些樣式可能比其他樣式需要更多時間來處理,并且時間隨著受一個或多個樣式更改影響的元素數(shù)量的增加而增加。 解決此問題的合適方法是塊元素修改器(BEM)方法。它提供了很好的性能優(yōu)勢,因為類匹配符合BEM方法,是現(xiàn)代瀏覽器中最快的選擇器。
布局
一個主要的性能瓶頸是布局抖動。在js重新計算元素節(jié)點(diǎn)的位置和形狀時,會導(dǎo)致瀏覽器重新布局。這樣,當(dāng)快速連續(xù)幾次完成時,會導(dǎo)致強(qiáng)制同步布局。 在這篇文章中, Google的Paul Lewis,強(qiáng)調(diào)了可以采取的各種優(yōu)化措施,以防止強(qiáng)制同步布局。
繪制
瀏覽器在開始填充屏幕像素時發(fā)生繪畫。這包括在屏幕上繪制所有視覺元素(譯者注:即在渲染樹上的節(jié)點(diǎn)都會被繪制,不管它在不在屏幕視窗內(nèi)), 這會生成多個平面,叫圖層。當(dāng)需要大面積繪制時,尤其是頁面滾動時,繪制同樣會導(dǎo)致性能問題。
繪制分析器,如上圖。這讓我們很容易就知道頁面的哪些區(qū)域被繪制和什么時候繪制的。
第一個多選框,Paint flashing,勾上之后頁面會以綠色高亮被重新繪制的部分。 這個頻率可以告訴我們繪畫是否會影響渲染管道上的性能問題。
我們看看上面這張圖,可以看到在頁面滾動時只有滾動條被重新繪制了。表明Scotch.io網(wǎng)站的主頁上有做瀏覽器繪制的優(yōu)化。
合成層(Layer Composition)
這是瀏覽器渲染管道的最后一步,它包含了重要的瀏覽器結(jié)構(gòu)-圖層(Layers)。瀏覽器引擎通過首先考慮樣式和元素以及它們的排序方式來進(jìn)行一些層管理。 然后嘗試找出頁面所需的圖層并相應(yīng)地更新圖層樹。
接下來,瀏覽器合成這些圖層并在屏幕上顯示它們。 當(dāng)瀏覽器必須繪制彼此重疊的頁面元素并且彼此存在于同一層中時,會出現(xiàn)由于繪制而導(dǎo)致的性能瓶頸。
要解決此問題,所涉及的元素必須存在于單獨(dú)的層中。 這可以通過改變CSS屬性并將其屬性設(shè)置為transform來實(shí)現(xiàn):
<element_to_promote> {will-change: transform; } 復(fù)制代碼然而,應(yīng)該注意的是,層的增加意味著花在層管理和合成上的時間增加。 使用Chrome開發(fā)工具,可以查看頁面上的所有圖層,如下所示:
打開chrome開發(fā)者工具,點(diǎn)擊hamburger菜單按鈕(三個豎著的點(diǎn)),選擇more Tools,選擇Layers。
轉(zhuǎn)載于:https://juejin.im/post/5c5410b3e51d450135283ad2
總結(jié)
 
                            
                        - 上一篇: 【Linux】rpm常用命令及rpm参数
- 下一篇: 常用扩展方法
