摘要:當(dāng)用戶滾動頁面時,合成線程會通知主線程更新頁面中最新可見部分的位圖。但是,如果主線程響應(yīng)地不夠快,合成線程不會保持等待,而是馬上繪制已經(jīng)生成的位圖,還沒準(zhǔn)備好的部分用白色進行填充。
動畫做多了,自然就要考慮性能,我打算出一個系列的日志,詳細的講解一下網(wǎng)頁動畫性能相關(guān)的知識,如果你已經(jīng)可以運用css3 canvas來做動畫,可以來參考一下。
目前我做的最復(fù)雜的動畫就是360搜索中PC端的天氣動畫。
共包含14個動畫場景,每個場景基本由1-3個獨立的動畫疊加而成,抽象動畫共12個,從開發(fā)到優(yōu)化完成共分為四期完成,一二期所有的動畫均使用canvas完成,三期四期對動畫性能進行大幅度改進,重構(gòu)了部分代碼。其中兼容低倍屏、高倍屏,canvas繪制的折線圖瀏覽器兼容到IE6(具體實現(xiàn)參見:基于canvas折線圖統(tǒng)計圖),動畫兼容到IE9,低版本瀏覽器動畫顯示靜態(tài)圖片。所以以下我所有分析均依賴于該項目。
量化流暢的動畫首先我們先來簡單的介紹一下動畫原理,其實動畫本身是不動的,它的實現(xiàn)原理是利用人眼的“視覺暫留”現(xiàn)象,在段時間內(nèi)連續(xù)播放數(shù)副精致的畫面,使肉眼銀視覺殘象產(chǎn)生錯覺,而產(chǎn)生“動”的概念。
相關(guān)概念
正常情況下瀏覽器渲染刷新頻率穩(wěn)定在60fps左右,人眼是可以看到流暢平滑的動畫的,一般來講低于30fps的動畫,就會有卡頓。
工欲善其事必先利其器來了解一下,怎樣使用chrome這把利刃。
FPS Meter
使用這個工具你可以檢測當(dāng)前瀏覽器GPU渲染動畫的幀率。
?? 高亮網(wǎng)頁中需要重繪的區(qū)域
?? 將需要重回的區(qū)域用橘黃色的邊框標(biāo)注
?? 繪制幀率,幀速率分布,以及GPU 緩存
?? 展示頁面中減慢滾動的區(qū)域
?? 強制媒體類型來測試繪制和屏幕渲染
showImg("https://static.imwineki.cn/static/upload/20170208/nYTKd_0V8cmm16pHCgPk5Nhh");
Timeline
具體使用方式可以參考:chrome官方文檔
profiles
taskmanager
瀏覽器內(nèi)核各廠出品的瀏覽器所用的渲染引擎不盡相同: IE使用Trident ,F(xiàn)ireFox使用Gecko ,Safari使用WebKit ,Chrome 28+ 和 Opera 15+使用的是Blink(WebKit的分支)
現(xiàn)代的瀏覽器通常會有兩個重要的執(zhí)行線程,這2個線程協(xié)同工作來渲染一個網(wǎng)頁:
一般情況下,主線程負責(zé):
合成線程負責(zé):
長時間執(zhí)行 JavaScript 或渲染一個很大的元素會阻塞主線程,在這期間,它將無法響應(yīng)用戶的交互。
相反,合成線程則會盡量去響應(yīng)用戶的交互。當(dāng)一個頁面發(fā)生變化時,由于當(dāng)今大多數(shù)設(shè)備的屏幕刷新率都是 60次/秒,所以合成線程也會以每秒60 幀的間隔去不斷重繪這個頁面,即使這個頁面不完整。
當(dāng)用戶滾動頁面時,合成線程會通知主線程更新頁面中最新可見部分的位圖。但是,如果主線程響應(yīng)地不夠快,合成線程不會保持等待,而是馬上繪制已經(jīng)生成的位圖,還沒準(zhǔn)備好的部分用白色進行填充。
也就是說js是單線程的,但瀏覽器是多線程的,感興趣的小伙伴可以看一下我之前翻譯的谷歌日志瀏覽器多進程架構(gòu)。
瀏覽器的渲染機制大多數(shù)設(shè)備的屏幕刷新率都是 60次/秒,瀏覽器對每一幀畫面的渲染工作需要在16毫秒(1秒 / 60 = 16.66毫秒)之內(nèi)完成。但實際上,在渲染某一幀畫面的同時,瀏覽器還有一些額外的工作要做(比如渲染隊列的管理,渲染線程與其他線程之間的切換等等)。因此單純的渲染工作,一般需要控制在10毫秒之內(nèi)完成,才能達到流暢的視覺效果。如果超過了這個時間限度,頁面的渲染就會出現(xiàn)卡頓效果,也就是常說的jank,它是很糟糕的用戶體驗。
在web頁面中,代碼就是經(jīng)過大概以下步驟轉(zhuǎn)換成屏幕上的顯示像素:
1.JavaScript:一般來說,我們會使用JavaScript來實現(xiàn)一些視覺變化的效果。
2.計算樣式:這個過程是根據(jù)CSS選擇器,比如.headline或.nav > .nav_item,對每個DOM元素匹配對應(yīng)的CSS樣式。這一步結(jié)束之后,就確定了每個DOM元素上該應(yīng)用什么CSS樣式規(guī)則。
3.布局:上一步確定了每個DOM元素的樣式規(guī)則,這一步就是具體計算每個DOM元素最終在屏幕上顯示的大小和位置。web頁面中元素的布局是相對的,因此一個元素的布局發(fā)生變化,會聯(lián)動地引發(fā)其他元素的布局發(fā)生變化。比如,
元素的寬度的變化會影響其子元素的寬度,其子元素寬度的變化也會繼續(xù)對其孫子元素產(chǎn)生影響。因此對于瀏覽器來說,布局過程是經(jīng)常發(fā)生的。4.繪制:本質(zhì)上就是填充像素的過程。包括繪制文字、顏色、圖像、邊框和陰影等,也就是一個DOM元素所有的可視效果。一般來說,這個繪制過程是在多個層上完成的。
5.渲染層合:由上一步可知,對頁面中DOM元素的繪制是在多個層上進行的。在每個層上完成繪制過程之后,瀏覽器會將所有層按照合理的順序合并成一個圖層,然后顯示在屏幕上。對于有位置重疊的元素的頁面,這個過程尤其重要,因為一旦圖層的合并順序出錯,將會導(dǎo)致元素顯示異常。
上述過程的每一步中都有發(fā)生jank的可能,因此一定要弄清楚你的代碼將會運行在哪一步。
雖然在理論上,頁面的每一幀都是經(jīng)過上述的流水線處理之后渲染出來的,但并不意味著頁面每一幀的渲染都需要經(jīng)過上述五個步驟的處理。實際上,對視覺變化效果的一個幀的渲染,有這么三種 常用的 流水線:
1.JS / CSS > 計算樣式 > 布局 > 繪制 > 渲染層合并
如果你修改一個DOM元素的”layout”屬性,也就是改變了元素的樣式(比如寬度、高度或者位置等),那么瀏覽器會檢查哪些元素需要重新布局,然后對頁面激發(fā)一個reflow過程完成重新布局。被reflow的元素,接下來也會激發(fā)繪制過程,最后激發(fā)渲染層合并過程,生成最后的畫面。
2.JS / CSS > 計算樣式 > 繪制 > 渲染層合并
如果你修改一個DOM元素的“paint only”屬性,比如背景圖片、文字顏色或陰影等,這些屬性不會影響頁面的布局,因此瀏覽器會在完成樣式計算之后,跳過布局過程,只做繪制和渲染層合并過程。
3.JS / CSS > 計算樣式 > 渲染層合并
如果你修改一個非樣式且非繪制的CSS屬性,那么瀏覽器會在完成樣式計算之后,跳過布局和繪制的過程,直接做渲染層合并。第三種的性能最為理想,一般來說對于動畫和滾動這種復(fù)合很重的渲染,我們就盡量向第三種靠攏。
性能優(yōu)化是一門減法藝術(shù),我們要本著經(jīng)歷簡化頁面徐然過程,然后使每一步的渲染盡可能高效。
瀏覽器中CPU vs GPU,如何抉擇?我們先來說說GPU,大多數(shù)手機、 平板電腦、 和計算機都配備了GPU芯片,GPU有著非常專業(yè)的定位,這意味著GPU非常擅長做某些事情(比如繪圖),但在其他方面則沒什么優(yōu)勢。
現(xiàn)在,我們來看看CPU和GPU的內(nèi)部特點
CPU(Central Processing Unit),GPU(Graphics Processing Unit)翻譯過來,第一個叫做中央處理器,后者叫做視覺處理器,換言之,同樣是計算機中用于計算的核心組件,CPU主要負責(zé)通用計算,GPU主要負責(zé)專用計算。我們來看看下面的這個圖理解一下:
翻譯一下:
翻譯一下:
可以看到,CPU中包含Control(控制層),Cache(緩存層),ALU(算術(shù)邏輯單元),其中ALU是主要負責(zé)進行簡單運算的。而GPU中則可以明顯的看到包含大量的ALU模塊和少量的Cache和Control模塊。
算術(shù)邏輯單元(英語:Arithmetic Logic Unit, ALU)[1]是中央處理器的執(zhí)行單元,是所有中央處理器的核心組成部分,由及閘和或閘構(gòu)成的算數(shù)邏輯單元,主要功能是進行二進制的算術(shù)運算,如加減乘(不包括整數(shù)除法)。基本上,在所有現(xiàn)代CPU體系結(jié)構(gòu)中,二進制都以二補數(shù)的形式來表示。 -----維基百科
所以可以清晰地從結(jié)構(gòu)中看出,CPU更擅長于邏輯控制,串行運算,GPU更擅長于大規(guī)模并發(fā)計算。舉一個簡單的例子,一個教授,帶著20個學(xué)生完成一個項目,現(xiàn)在項目需要處理1000次100以內(nèi)的加減乘除運算,這項工作其實并不需要任何邏輯處理,只是大量的工作量的堆疊,這時,就不需要教授親力親為,教授可以將任務(wù)分配給這20個學(xué)生分工完成這項工作,其中教授的角色就相當(dāng)于CPU,20個學(xué)生總體相當(dāng)于GPU,每個學(xué)生就等于一個ALU。
GPU的處理圖像的優(yōu)勢:
GPU的慢在于:
JS動畫
缺點:JavaScript在瀏覽器的主線程中運行,而其中還有很多其他需要運行的JavaScript、樣式計算、布局、繪制等對其干擾。這也就導(dǎo)致了線程可能出現(xiàn)阻塞,從而造成丟幀的情況。
優(yōu)點:JavaScript的動畫與CSS預(yù)先定義好的動畫不同,可以在其動畫過程中對其進行控制:開始、暫停、回放、中止、取消都是可以做到的。而且一些動畫效果,比如視差滾動效果,只有JavaScript能夠完成。
CSS動畫
缺點:缺乏強大的控制能力。而且很難以有意義的方式結(jié)合到一起,使得動畫變得復(fù)雜且易于出問題。
優(yōu)點:瀏覽器可以對動畫進行優(yōu)化。它必要時可以創(chuàng)建圖層,然后在主線程之外運行,也就是開啟GPU加速。
一般來說,Chrome中滿足以下任意情況就會創(chuàng)建圖層:
需要注意的是,如果圖層中某個元素需要重繪,那么整個圖層都需要重繪。比如一個圖層包含很多節(jié)點,其中有個gif圖,gif圖的每一幀,都會重回整個圖層的其他節(jié)點,然后生成最終的圖層位圖。所以這需要通過特殊的方式來強制gif圖屬于自己一個圖層(translateZ(0)或者translate3d(0,0,0)),CSS3的動畫也是一樣。
展望通過web workers 這樣的多線程來實現(xiàn)動畫
好啦!基本概念已經(jīng)鋪墊完了,感興趣的話,就來看看在業(yè)務(wù)線中如何小試牛刀。網(wǎng)頁動畫性能日志(二)
轉(zhuǎn)載請說明出處!
參考鏈接:
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/108854.html
摘要:性能統(tǒng)計有助于幫我們檢測網(wǎng)站的用戶體驗。這樣,我們就輕輕松松的統(tǒng)計到了首屏?xí)r間。下一章,我們將繼續(xù)聊聊百度移動版首頁那些事。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼): https://segmentfault.com/blog/frontenddriver 上一篇文章我們討論了,如何進行前端日志打點統(tǒng)計: https://segm...
摘要:性能統(tǒng)計有助于幫我們檢測網(wǎng)站的用戶體驗。這樣,我們就輕輕松松的統(tǒng)計到了首屏?xí)r間。下一章,我們將繼續(xù)聊聊百度移動版首頁那些事。 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼): https://segmentfault.com/blog/frontenddriver 上一篇文章我們討論了,如何進行前端日志打點統(tǒng)計: https://segm...
摘要:回過頭來發(fā)現(xiàn),我們的項目,雖然在服務(wù)端層面做好了日志和性能統(tǒng)計,但在前端對異常的監(jiān)控和性能的統(tǒng)計。對于前端的性能與異常上報的可行性探索是有必要的。這是我們頁面加載性能優(yōu)化需求中主要上報的相關(guān)信息。 概述 對于后臺開發(fā)來說,記錄日志是一種非常常見的開發(fā)習(xí)慣,通常我們會使用try...catch代碼塊來主動捕獲錯誤、對于每次接口調(diào)用,也會記錄下每次接口調(diào)用的時間消耗,以便我們監(jiān)控服務(wù)器接口...
摘要:在樣式代碼添加錄制性能日志如下可見,已經(jīng)不存在繪制的步驟了。下面通過一段代碼模擬頁面進入的過程,來演示這個問題運行效果如下可以看到,固定定位的黃色元素是在動畫結(jié)束后才突然出現(xiàn)的。 對于移動端的Web單頁應(yīng)用來說,為了達到媲美原生應(yīng)用的效果,頁面過渡動畫是必不可少的。常用的頁面過渡動畫包括: 位移——當(dāng)前頁向左側(cè)或右側(cè)水平移出可視區(qū),下一頁由反方向移入可視區(qū)。 不透明度變化——當(dāng)前頁淡...
閱讀 1507·2023-04-26 00:25
閱讀 906·2021-09-27 13:36
閱讀 929·2019-08-30 14:14
閱讀 2171·2019-08-29 17:10
閱讀 1006·2019-08-29 15:09
閱讀 1942·2019-08-28 18:21
閱讀 962·2019-08-26 13:27
閱讀 971·2019-08-26 10:58