最近在開發小程序,與vue相似,它們都有生命週期這回事。css
onLoad 監聽頁面加載html
onReady 監聽頁面初次渲染完成前端
onShow 監聽頁面顯示vue
究竟是什麼意思?android
因此這又觸碰到了個人知識盲區,不過項目在磕磕絆絆中完成的差很少了,可是遇到了CSS3動畫渲染的性能問題,因此我也是被逼的,再回過頭來從瀏覽器渲染網頁的流程出發,去找動畫卡頓的癥結。ios
瀏覽器渲染網頁的流程以下:css3
使用 HTML 建立文檔對象模型(DOM)web
使用 CSS 建立 CSS 對象模型(CSSOM)chrome
基於 DOM 和 CSSOM 執行腳本(Scripts)json
合併 DOM 和 CSSOM 造成渲染樹(Render Tree)
使用渲染樹佈局(Layout)全部元素
渲染(Paint)全部元素
能夠結合Alon的這篇前端性能優化和安卓開發者選項的顯示頁面佈局。
如何判斷手機app是native,webview仍是hybird?
簡單說下,app中的一大塊是白色的沒有紅線標記出來的,可是上面有按鈕,圖片等時,就是webview,也就是經過一個僞瀏覽器去請求到的數據,斷網時打開app沒有任何東西顯示在上面
onLoad 監聽頁面加載
在渲染完界面以後,也就是經過.json中的配置項生成native界面後,開始渲染webview的部分,一個頁面只會調用一次。
onReady 監聽頁面初次渲染完成
一個頁面只會調用一次,表明頁面已經準備穩當,能夠和視圖層進行交互。
onShow 監聽頁面顯示
每次打開頁面都會去調用其中的函數。
應該放在onShow裏,由於這樣我每次打開都能看到動畫。
有一個前提必需要提,前端開發者們都知道,瀏覽器是單線程運行的。可是咱們要明確如下幾個概念:單線程,主線程和合成線程。
雖說瀏覽器執行js是單線程執行(注意,是執行,並非說瀏覽器只有1個線程,而是運行時,runing),但實際上瀏覽器的2個重要的執行線程,這 2 個線程協同工做來渲染一個網頁:主線程和合成線程。
通常狀況下,主線程負責:運行 JavaScript;計算 HTML 元素的 CSS 樣式;頁面的佈局;將元素繪製到一個或多個位圖中;將這些位圖交給合成線程。
相應地,合成線程負責:經過 GPU 將位圖繪製到屏幕上;通知主線程更新頁面中可見或即將變成可見的部分的位圖;計算出頁面中哪部分是可見的;計算出當你在滾動頁面時哪部分是即將變成可見的;當你滾動頁面時將相應位置的元素移動到可視區域。
緣由就是主線程和合成線程的調度不合理。
下面來詳細說一下調度不合理的緣由。
在使用height,width,margin,padding做爲transition的值時,會形成瀏覽器主線程的工做量較重,例如從margin-left:-20px渲染到margin-left:0,主線程須要計算樣式margin-left:-19px,margin-left:-18px,一直到margin-left:0,並且每一次主線程計算樣式後,合成進程都須要繪製到GPU而後再渲染到屏幕上,先後總共進行20次主線程渲染,20次合成線程渲染,20+20次,總計40次計算。
主線程的渲染流程,能夠參考瀏覽器渲染網頁的流程:
使用 HTML 建立文檔對象模型(DOM)
使用 CSS 建立 CSS 對象模型(CSSOM)
基於 DOM 和 CSSOM 執行腳本(Scripts)
合併 DOM 和 CSSOM 造成渲染樹(Render Tree)
使用渲染樹佈局(Layout)全部元素
渲染(Paint)全部元素**
也就是說,主線程每次都須要執行Scripts,Render Tree ,Layout和Paint這四個階段的計算。
而若是使用transform的話,例如tranform:translate(-20px,0)到transform:translate(0,0),主線程只須要進行一次tranform:translate(-20px,0)到transform:translate(0,0),而後合成線程去一次將-20px轉換到0px,這樣的話,總計1+20計算。
可能會有人說,這才提高了19次,有什麼好性能提高的?
假設一次10ms。
那麼就減小了約190ms的耗時。
會有人說,辣雞,才190ms,無所謂。
那麼若是margin-left是從-200px到0呢,一次10ms,10ms*199≈2s。
還會有人說,辣雞,也就2s,無所謂。
你忘了單線程這回事了嗎?
若是網頁有3個動畫,3*2s=6s,就是6s的性能提高。
因爲數據是猜想的,因此暫時不考慮其真實性,文章後面我使用chrome devtools的performance作了一個實驗。
要知道,在"客戶至上"的今天,好的用戶體驗是全部產品的必須遵照的一條規則,不管是對於開發者仍是產品經理,追求極致的性能都是咱們打造一個好的產品所必備的品質。
可能看了個人略不專業的分析後,你們對主線程,合成線程以及它們在2種性能不一樣動畫方案上的工做流程還不是很瞭解,能夠去看一篇翻譯過來的博客(英文原版連接已經失效了):深刻瀏覽器理解CSS animations 和 transitions的性能問題
這篇文章完美講述了瀏覽器主線程和合成線程的區別,而且舉了一個高度從100px變化到200px的2種動畫方案的對比,對主線程和合成線程的整個工做流程作了很詳盡的講解,真心建議認真閱讀一遍。
回過頭來總結下,css3動畫卡頓的解決方案:
在使用css3 transtion作動畫效果時,優先選擇transform,儘可能不要使用height,width,margin和padding。
transform爲咱們提供了豐富的api,例如scale,translate,rotate等等,可是在使用時須要考慮兼容性。但其實對於大多數css3來講,mobile端支持性較好,desktop端支持性須要格外注意。
補充:爲了加強本文的說服力,特意回家作了一個實驗,代碼以下。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.margin-transition{
/* margin-left: 0; */
background: rgba(0,0,255,0.3);
transition: margin-left 1s;
}
.transform-transition{
/* transform: translate(0,0); */
background: rgba(0,255,0,0.3);
transition: transform 1s;
}
.common{
height: 300px;
width: 300px;
}
</style>
</head>
<body>
<div class="margin-transition common" id="marginTransition">
<p>transition:margin-left 1s</p>
</div>
<div class="transform-transition common" id="transformTransition">
<p>transition:tranform 1s</p>
</div>
<button id="control">見證奇蹟</button>
<script>
var btn = document.getElementById('control');
var marginTransition = document.getElementById('marginTransition');
var transformTransition = document.getElementById('transformTransition');
btn.addEventListener("click",function(){
console.log(marginTransition.style,transformTransition.style)
marginTransition.style.marginLeft = "500px";
transformTransition.style.transform = "translate(500px,0)"
})
</script>
</body>
</html>
我將主要藉助chrome devtools的performance工具對比兩者的性能差別。
先來看margin動畫,動態修改DOM節點的margin-left值從0到500px;。
transition: margin-left 1s;
再來看下transform動畫,動態修改DOM節點的transform值從translate(0,0)到translate(500px,0)。
transition: transform 1s;
可能圖片不是很好地能說明性能差別,那麼咱們來列一張耗時對比表,方便咱們計算。
耗時 | margin | transform |
---|---|---|
Summery | 3518ms | 2286ms |
Scripting | 1.8ms | 2.9ms |
Rendering | 22.5ms | 6.9ms |
Painting | 9.7ms | 1.6ms |
Other | 39.3ms | 25.2ms |
Idle( browser is waiting on the CPU or GPU to do some processing) | 3444.4ms | 2249.8ms |
GPU使用率 | 4.1MB | 1.7MB |
經過上表咱們能夠計算出明margin,transform與transition組合實現CSS3動畫效果時的性能差別參數。
關鍵性能參數 | margin | transform |
---|---|---|
實際動畫耗時(總時間 減去 空閒時間) | 73.6ms | 36.2ms |
計算得出,transform動畫耗時約等於margin動畫耗時的0.49倍,性能優化50%。
因爲我對Other的所作的具體事情不是很清楚,因此這裏的實際動畫時間也有可能還要減掉Other中的時間,下表是咱們減掉後的數據。
關鍵性能參數 | margin | transform |
---|---|---|
實際動畫耗時(總時間 減去 其餘時間和空閒時間) | 34.3ms | 11ms |
計算得出,transform動畫耗時約等於margin動畫耗時的0.32倍,性能優化接近70%。
也就是說,不管咱們減去仍是不減去Other的時間,咱們採用transform實現動畫的方式都比margin動畫快。
不精確的得出一個小結論:transform比margin性能好50%~70%。
雖然會有50%~70%的性能提高,可是須要注意硬件差別,硬件好的狀況下可能不能發現卡頓或者其餘的一些性能上的問題。
例如在開發小程序的過程當中,模擬器是位於desktop端的,所以它的硬件性能性能更好,例如CPU,GPU。可是一旦在mobile端運行,例如ios或者android上運行時,就可能會出現性能問題,這就是由於移動端的硬件條件遜於PC端致使的。
因此說,性能問題是一直存在的,只不過硬件差別會致使性能影響的程度不一樣。
因此咱們再次回過頭來,總結出css3動畫卡頓的解決方案:
在使用css3 transtion作動畫效果時,優先選擇transform,儘可能不要使用height,width,margin和padding。