摘要:本文是求索的動畫快于嗎為何的續(xù)文。沒有集中繪制,每個都在一個事件回調(diào)函數(shù)上下文中處理,有多少個就有多少個上下文有集中繪制。測試過程中為了比較好的效果用了隨機數(shù)。
本文是求索:GSAP的動畫快于jQuery嗎?為何? 的續(xù)文。GSAP是一個js動畫插件,它聲稱“20x faster than jQuery”,是什么讓它這么快呢?
每當(dāng)有這樣的問題的時候,我們可以通過以下步驟來確定一個未知的解決方案的性能優(yōu)化是怎么做到/偽造的:
黑盒:從官方用例來看,究竟有多快,快在哪兒
白盒:看看官方用例之內(nèi),框架怎么做到優(yōu)化的
do { 提出假設(shè),自己構(gòu)建用例測試 } while (假設(shè)沒有得到驗證);
得出結(jié)論
對前文的一些補充本文是整個探究過程的后兩個部分。
本文可能需要你知道的一些知識
requestAnimationFrame相關(guān):
MSDN
DEV.OPERA 翻譯
瀏覽器工作原理
瀏覽器的渲染原理簡介
瀏覽器的工作原理:新式網(wǎng)絡(luò)瀏覽器幕后揭秘
瀏覽器提供的調(diào)試工具
MSDN - IE11的UI響應(yīng)測量工具
developers.google - chrome的快照相關(guān)頁面
注:這里沒有更好的inspector快照內(nèi)容介紹(翻譯的,或是足夠詳盡的),如果你知道的話不妨告訴我喲~
為了下文閱讀方便,這里從profiler得到的結(jié)果角度,提一下瀏覽器里,從定時器被激活,到用戶看到圖形的主要流程:
CHROME
腳本運行(黃色)->回流與重計算(紫色)->重繪(綠色)->其他(白色,探查器的相關(guān)內(nèi)容)
IE11
加載(深藍色)->腳本運行(紅色)->內(nèi)存垃圾回收(黃色)->回流與重計算(綠色)->重繪(紫色)->其他(灰色,探查器的相關(guān)內(nèi)容)
注意到chrome和IE11的重繪與回流/重計算的表示顏色是相反的。
下文中的測試,chrome的計時區(qū)間是一個gc的間隔(50s左右)(因為在chrome里,F(xiàn)PS和內(nèi)存占用有比較小的反相關(guān),內(nèi)存占用越多,F(xiàn)PS越低),而IE則采用10s的間隔(因為在IE 11里,F(xiàn)PS和內(nèi)存占用看不出相關(guān)性)。
同時,不對不支持requestAnimationFrame的瀏覽器做出評測。
注:這里也沒有測試firefox,因為目前還沒有找到靠譜的測量UI響應(yīng)的功能,如果有請@我,多謝
最后,為了下文比較方便,我們在chrome和IE11下再次測試官方給的用例,獲得表格(單位FPS,為平均值,后面均一樣,不再次說明):
瀏覽器 | chrome | IE 11 |
GSAP test: jQuery | 14 | 22 |
GSAP test: GSAP | 45 | 53 |
根據(jù)前文所述,我們得到以下假設(shè):
jQuery的定時器采用的是setInterval,受到瀏覽器重繪上限的控制,而GSAP采用requestAnimationFrame,完全將重繪交給瀏覽器管理,以獲得更好地重繪性能
jQuery每次都是多帶帶修改一個DOM的style,而GSAP是計算離線的style,然后再賦給DOM。這導(dǎo)致了不一樣的時間開銷。
jQuery沒有集中繪制,每個DOM都在一個事件回調(diào)函數(shù)上下文中處理,有多少個DOM就有多少個上下文;GSAP有集中繪制。同時jQuery是過程化的,GSAP是面向?qū)ο蟮?。這讓jQuery非常難以做到集中控制繪制。jQuery會將DOM的引用一路傳遞到最終改變DOM的style函數(shù)中,這在調(diào)用過程中也會非常浪費空間。這些也都導(dǎo)致了不一樣的時間開銷。
是這樣的嗎?
測試1:setTimeout vs requestAnimationFrame之前已經(jīng)有這樣的測試了:《setInterval與requestAnimationFrame的時間間隔測試》,但有以下弊?。?/p>
在那個測試沒有進行實際的任務(wù),僅僅是空循環(huán)判斷時間而已
——改進:在這里我做了一個繪制隨機div的操作,一方面盡量接近GSAP的用例,另一方面盡量簡短,以減少變量對測試的影響。
測試所用的時間測量非常不準(zhǔn)確
——改進:測量結(jié)果,用的是chrome和IE11瀏覽器本身提供的原生性能分析工具,以取得盡量準(zhǔn)確的幀率。
在body內(nèi)部填入N(N=500,可以改變這個值)個div,設(shè)置它們的圓角、背景屬性。然后在每幀里面隨機改變他們的top、left(對應(yīng)著回流)、transform(對應(yīng)著重繪)值,這樣,可以讓每幀的繪制里頁面常見的繪制操作耗時均等。大致就是要繪制以下的效果。
測試代碼如下:
http://jsfiddle.net/humphry/HNysW/4/
CHROME結(jié)果:
setTimeout(fn,10)
setTimeout(fn,13)
setTimeout(fn,16)
requestAnimationFrame
setInterval(fn,16)
- “我去,幀率沒有太大區(qū)別嘛?!?br>
- “該不是因為我們沒有測IE嘛?”
恩,那么我們進入IE11,。下圖是requestAnimationFrame的測試結(jié)果,可惜沒有統(tǒng)計,也不支持導(dǎo)出數(shù)據(jù),不能知道平均幀率。
我將setInterval的結(jié)果印在requestAnimationFrame上,兩者的對比可見下圖:
- “并沒有沒有顯著的提升啊?!?br>
- “看起來一定是我們沒有夠數(shù)據(jù)量的緣故?!?/p>
來吧,調(diào)節(jié)點的數(shù)量:
我們現(xiàn)在放進去1000個小點,我們在IE11下的結(jié)果對比以下:
- “要說有那么一點優(yōu)化,卻是一點優(yōu)化都看不出來的感覺呢。”
- “看起來一定是我們沒有測小繪制壓力的緣故?!?/p>
或者調(diào)節(jié)成200個小點呢,我們在IE11下幀率對比一下:
再綜合一下數(shù)據(jù):
小點個數(shù) | 200 | 500 | 1000 | |||
瀏覽器 | chrome | IE 11 | chrome | IE 11 | chrome | IE 11 |
requestAnimationFrame | 53 | 60 | 30 | 32 | 17 | 19 |
setInterval 16 | 53 | 60 | 29 | 30 | 12 | 19 |
- “為什么,為什么看不出來效果呀 擦 擦”
- “阿瑪,我們不是被涮了吧!”
- “不可能!他們說得真真兒的,究竟是什么地方不對呢……我們是不是把回流和重繪弄得太均勻了啊”
……好吧,那么我構(gòu)造一個這樣的文檔結(jié)構(gòu),div套div套div套div套……讓它們都為inline-block,以獲得包裹的效果……
body{ height:100% ; background:#000; overflow:hidden; } html{ height: 100%; } div{ padding: 1px 3px 2px 0; border-top: 2px solid; display: inline-block; }
大概像是這樣。
這個時候改變最里面的div的寬度,就會導(dǎo)致大面積的回流了。
http://jsfiddle.net/humphry/SwLY7/1/
可以看到,占大比例的是回流(紫色部分)。hover到layout處,可以看到:
全員參與回流,CPU什么的一定很帶感呢。
結(jié)果:
參與嵌套的DIV數(shù)量 (reflow) | 200 | 500 | 700 | 1000 | ||||
瀏覽器 | chrome | IE 11 | chrome | IE 11 | chrome | IE 11 | chrome | IE 11 |
requestAnimationFrame | 48 | 60 | 26 | 60 | 15 | 60 | 8 | (崩潰) |
setInterval 16 | 47 | 60 | 26 | 60 | 15 | 60 | 8 | (崩潰) |
我們來設(shè)置陰影,以期獲得較長的重繪時間:
一閃一閃亮晶晶~
http://jsfiddle.net/humphry/XdFqR/1/
如圖,綠色的重繪占據(jù)了大部分。
結(jié)果:
閃爍的星星數(shù)量(repaint) | 80 | 100 | 200 | |||
瀏覽器 | chrome | IE 11 | chrome | IE 11 | chrome | IE 11 |
requestAnimationFrame | 54 | 16 | 45 | 12 | 26 | 4 |
setInterval 16 | 47 | 16 | 38 | 10 | 24 | 5 |
- “……”
- “……盡管在chrome下是有一些提升,但是也沒有達到用例那么明顯,達到兩倍的關(guān)系呀阿瑪。”
我們來再回顧一次結(jié)果:
我們前面的三個測試:
隨機重排、縮放圓點測試:測試回流+重繪
嵌套inline-block大面積回流測試:測試回流
隨機陰影模糊半徑測試:測試重繪
基本上可以說明,在低渲染壓力/中等渲染壓力/高渲染壓力三種場景中,requestAnimationFrame里面的重繪性能平均比setInterval快1~5幀左右,而回流性能則沒有很大影響。
那么,GSAP是如何讓用例出現(xiàn)這么大的區(qū)別呢?chrome里快2倍,IE11里面快1倍,這不是一個輕易換用requestAnimationFrame就可以達到的結(jié)果。
我想到,setInterval這個函數(shù)其實并不是一次觸發(fā),而是針對每個DOM觸發(fā)的。在此之前的所有測試,皆是集中的計時器。因此,有了第四個測試:
測試4:集中計時器 VS 分散計時器 VS 集中rAF VS 分散rAF第四個測試,就是將前面的第一個和第三個測試改一下,將集中改成分散。方案是,擴展HTMLDivElement原型方法,然后讓每個DOM調(diào)用它,即可模擬在官方的jQuery測試用例中發(fā)生的事情。
HTMLDivElement.prototype.startAnimationOnMyOwn = function() { var that = this ; setInterval(function(){ repaint(that) ; } , 16) ; } ; for (var i = 0; i < NUM; i++) { allnodes[i].startAnimationOnMyOwn() ; }
測試1的去中心化版:
http://jsfiddle.net/humphry/pBwBx/
測試3的去中心化版:
http://jsfiddle.net/humphry/7fa64/
得到結(jié)果:
測試1·改(去中心化的重繪/requestAnimationFrame)
圓點數(shù)量 | 200 | 500 | 1000 | |||
瀏覽器 | chrome | IE 11 | chrome | IE 11 | chrome | IE 11 |
rAF (集中) | 53 | 60 | 30 | 32 | 17 | 19 |
rAF (去中心化) | 17 | 20 | 12 | 2 | 6 | 1 |
setInterval 16 (集中) | 53 | 60 | 29 | 30 | 12 | 19 |
setInterval 16 (去中心化) | 19 | 34 | 8 | 15 | 4 | 6 |
測試3·改(去中心化的重繪/requestAnimationFrame)
閃爍的陰影數(shù)量 | 80 | 100 | 200 | |||
瀏覽器 | chrome | IE 11 | chrome | IE 11 | chrome | IE 11 |
rAF (集中) | 54 | 16 | 45 | 12 | 26 | 4 |
rAF (去中心化) | 33 | 13 | 27 | 12 | 16 | 5 |
setInterval 16 (集中) | 47 | 16 | 38 | 10 | 24 | 5 |
setInterval 16 (去中心化) | 36 | 14 | 31 | 10 | 14 | 5 |
這個表中終于出現(xiàn)了非常大的數(shù)據(jù)波動,也符合GSAP的的測試結(jié)果,我們可以得出結(jié)論了。
得出結(jié)論比較直觀的所有結(jié)果比較:
setInterval是否比requestAnimationFrame更慢?
不是的。上表中的數(shù)據(jù)可以表明這一點,在短的回調(diào)里,造成重繪的相關(guān)代碼,requestAnimationFrame比setInterval稍微快一些;但是在長回調(diào)函數(shù)(多次構(gòu)造requestAnimationFrame,它們會被合到一個里面)里,requestAnimationFrame不比setInterval快。
這也是《理解WebKit:渲染主循環(huán)main loop和rAF》里說:“回調(diào)函數(shù)不能太大,不能占用太長時間,否則會影響頁面的響應(yīng)和繪制的頻率”的原因。
requestAnimationFrame最主要的意義,是降幀而非升幀,以防止丟幀。它的目的更類似于垂直同步,而非越快越好。
MSDN: 幀率不等或跳幀會使人感覺你的站點速度緩慢。如果降低動畫速度可以減少跳幀并有助于保持幀率一致,它可以使人感覺站點速度更快。
閱讀更多:http://creativejs.com/resources/requestanimationframe/
集中定時器造成重繪是否比分散定時器造成重繪快?
是的。這也是GSAP更快的原因。
測試需要改進嗎?
我認(rèn)為需要。測試過程中為了比較好的效果用了隨機數(shù)。其實生成隨機數(shù)的過程中也耗費了一定的時間,更好的測試中,可以用線性的變化替換隨機離散的數(shù)值變化,數(shù)據(jù)會更加穩(wěn)定。
同時,沒有測試firefox,很可惜,到目前為止,筆者依然沒有找到一款好使的分析UI的插件。
GSAP的用例是否說明了GSAP快于jQuery呢?
是的,這可以說明GSAP更快。但并非是在任何時候都更快。在我們需要粒子系統(tǒng)時快,在我們只需要繪制一兩個小交互時,它沒有提供非常明顯的性能優(yōu)化的可能性。后者可以直接用CSS3 Animation/Translation做,或者用jQuery達到全瀏覽器兼容。若出現(xiàn)了粒子系統(tǒng)這樣的大量元素重繪的需求,用GSAP是很好的選擇。
造成GSAP更快的原因,是由于jQuery的處理方式,非常不適合繪制大量節(jié)點。
再次摘抄用例:
tests.jquery = { tween:function(dot) { dot[0].style.cssText = startingCSS; var angle = Math.random() * Math.PI * 2; dot.delay(Math.random() * duration).animate({left:Math.cos(angle) * radius + centerX, top:Math.sin(angle) * radius + centerY, width:32, height:32}, duration, "cubicIn", function() { tests.jquery.tween(dot) }); } }; function toggleTest() { i = dots.length; while (--i > -1) { currentTest.tween(dots[i]); } }
在正常的項目執(zhí)行過程中,我們會使用jQuery.animate繪制大量元素嗎?有人可能會,但我不會這么做。
GSAP相對于jQuery的進步性,就在于集中繪制了所有需要動畫更新的元素;同時也有更多的插件供選擇,可以每過一幀改變更多的類型,而非僅僅是CSS樣式。
在項目中引入GSAP,需要引入以下三者:
耗費三個連接,和近25Kb來加載這個組件,獲得在有很大繪制任務(wù)時更快的動畫實現(xiàn),這個代價值得不值得,還是需要在具體需求具體分析了。
在最后,推薦一篇高大上全的文章:《編寫快速、高效的JavaScript代碼》。引用文中的一句話,做結(jié)語吧:
“正如我們所見,在JavaScript的引擎世界里面,有許多的隱藏的性能陷阱。但事實上并沒有性能提高的銀彈。只有當(dāng)你在測試環(huán)境中結(jié)合一系列的優(yōu)化,你才會意識到最大的性能獲益?!?/p>
更新list
v1.1
前端很多測試都不乏前人,早在HTML4時代就有人測試GUI Benchmark了:GuiMark,從他給出的用例來看,他主要測試了回流和重繪同時存在的情形。也可以參考一下測試方式。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/87463.html
摘要:本文已完結(jié),請看下文求索的動畫快于嗎為何續(xù)本文源自對問題動畫性能優(yōu)于的原理是什么的回答。是這樣的嗎請看下文求索的動畫快于嗎為何續(xù) 本文已完結(jié),請看下文: > 求索:GSAP的動畫快于jQuery嗎?為何?/續(xù) 本文源自對問題《GSAP js動畫性能優(yōu)于jQuery的原理是什么?》的回答。GSAP是一個js動畫插件,它聲稱20x faster than jQuery,是什么讓...
摘要:現(xiàn)在又多了一種實現(xiàn)動畫的方案,那就是還在草案當(dāng)中的方法。這個方法就是傳遞給的回調(diào)函數(shù)。為回調(diào)函數(shù)一個簡單的例子模擬一個進度條動畫,初始寬度為在函數(shù)中將進度加然后再更新到寬度上,在進度達到之前,一直重復(fù)這一過程。 HTML5/CSS3時代,我們要在web里做動畫選擇其實已經(jīng)很多了: 你可以用CSS3的animattion+keyframes; 你也可以用css3的transition...
摘要:現(xiàn)在又多了一種實現(xiàn)動畫的方案,那就是還在草案當(dāng)中的方法。這個方法就是傳遞給的回調(diào)函數(shù)。為回調(diào)函數(shù)一個簡單的例子模擬一個進度條動畫,初始寬度為在函數(shù)中將進度加然后再更新到寬度上,在進度達到之前,一直重復(fù)這一過程。 HTML5/CSS3時代,我們要在web里做動畫選擇其實已經(jīng)很多了: 你可以用CSS3的animattion+keyframes; 你也可以用css3的transition...
摘要:現(xiàn)在又多了一種實現(xiàn)動畫的方案,那就是還在草案當(dāng)中的方法。這個方法就是傳遞給的回調(diào)函數(shù)。為回調(diào)函數(shù)一個簡單的例子模擬一個進度條動畫,初始寬度為在函數(shù)中將進度加然后再更新到寬度上,在進度達到之前,一直重復(fù)這一過程。 HTML5/CSS3時代,我們要在web里做動畫選擇其實已經(jīng)很多了: 你可以用CSS3的animattion+keyframes; 你也可以用css3的transition...
摘要:雖然沒有視覺效果,但這就是基本的值動畫。有專門的位置可以查詢緩動函數(shù)。另外,不要期望在不支持的瀏覽器上做動畫。是專業(yè)動畫庫,在大部分情況下,它也具備更好的動畫性能。 說到在網(wǎng)頁里創(chuàng)建動畫,你可能很快會想到j(luò)Query的animate()方法,或者css3的animation和transition?,F(xiàn)在,本文將介紹另一個web動畫的可選方案,GSAP。 GSAP的全名是GreenSock...
閱讀 3580·2023-04-25 20:09
閱讀 3770·2022-06-28 19:00
閱讀 3115·2022-06-28 19:00
閱讀 3129·2022-06-28 19:00
閱讀 3230·2022-06-28 19:00
閱讀 2917·2022-06-28 19:00
閱讀 3104·2022-06-28 19:00
閱讀 2703·2022-06-28 19:00