深入探究使JavaScript動畫流暢的一些方法
基于Javascript的動畫暗中同CSS過渡效果一樣,甚至更加快,這怎么可能呢?而Adobe和Google持續(xù)發(fā)布的富媒體移動網(wǎng)站的性能可媲美本地應(yīng)用,這又怎么可能呢?
本文逐一遍覽了基于Javascript的DOM動畫庫,如Velocity.js和GSAP,看其是如何比jQuery和CSS動畫效果更具性能的.
jQuery
讓我們先從基礎(chǔ)的開始: JavaScript 和 jQuery 被錯誤的混為一談了. JavaScript 動畫是很快的. jQuery 把它放慢了下來。為什么?因為 — 盡管jQuery非常強大 — 但成為一個性能強勁的動畫引擎從來都不是jQuery的設(shè)計目標(biāo):
- jQuery 不能避免 布局顛簸 ,這得歸因于它的代碼庫提供了動畫之外的多種用途.
- jQuery 的內(nèi)存消耗經(jīng)常會觸發(fā)垃圾回收,那樣會 時不時的讓動畫定格下來.
- jQuery 使用 setInterval 而不是 requestAnimationFrame (RAF) 來 保護(hù)新技術(shù)不受其自身的影響.
應(yīng)該注意到布局顛簸就是在動畫開始部分的不順暢,垃圾回收就是造成動畫期間不順暢的元兇, 而沒有使用RAF則會導(dǎo)致低幀率.
實現(xiàn)示例
避免造成布局顛簸的DOM查詢和更新組合:
var currentTop, currentLeft; /* With layout thrashing. */ currentTop = element.style.top; /* QUERY */ element.style.top = currentTop + 1; /* UPDATE */ currentLeft = element.style.left; /* QUERY */ element.style.left = currentLeft + 1; /* UPDATE */ /* Without layout thrashing. */ currentTop = element.style.top; /* QUERY */ currentLeft = element.style.left; /* QUERY */ element.style.top = currentTop + 1; /* UPDATE */ element.style.left = currentLeft + 1; /* UPDATE */
發(fā)生在更新之后的查詢會強制瀏覽器對頁面的計算式數(shù)據(jù)進(jìn)行重新計算 (同時會把新的更新效果考慮在內(nèi)). 這樣就會對動畫產(chǎn)生顯著的開銷,而這只是16毫秒微小間隔的運行超時.
類似的,實現(xiàn) RAF 并不必須是對你的現(xiàn)有代碼庫的顯著返工. 讓我們拿RAF的基礎(chǔ)實現(xiàn)同setInterval比較一下:
var startingTop = 0; /* setInterval: Runs every 16ms to achieve 60fps (1000ms/60 ~= 16ms). */ setInterval(function() { /* Since this ticks 60 times a second, we divide the top property's increment of 1 unit per 1 second by 60. */ element.style.top = (startingTop += 1/60); }, 16); /* requestAnimationFrame: Attempts to run at 60fps based on whether the browser is in an optimal state. */ function tick () { element.style.top = (startingTop += 1/60); } window.requestAnimationFrame(tick);
RAF 產(chǎn)生了推動動畫性能的最大可能性,你可以對你的代碼進(jìn)行單一的變更.
CSS 轉(zhuǎn)換
CSS轉(zhuǎn)換通過把動畫邏輯甩給瀏覽器本身去處理而超越了jQuery,這在以下幾方面是有效果的:(1)優(yōu)化DOM交互和內(nèi)存消耗以避免卡頓(顛簸),(2)利用引擎的RAF原則,(3)強制硬件加速(利用GPU的能力來提高動畫性能)。
然而,現(xiàn)實是,這些優(yōu)化也可以在JavaScript中直接執(zhí)行。GSAP已經(jīng)這樣做了多年。Velocity.js,一個新的動畫引擎,不僅利用了同樣的技術(shù),而且還向前多走了幾步——我們不久會探討這些。
面對事實,JavaScript動畫可以與CSS轉(zhuǎn)換競爭只是我們康復(fù)計劃的第一步。第二步是實現(xiàn)“JavaScript動畫實際上可以比CSS轉(zhuǎn)換更快”。
現(xiàn)在我們開始談?wù)凜SS變換的弱點:
- transition強制硬件加速會加大GPU消耗,高負(fù)荷情形下將導(dǎo)致運行不流暢。這種情況在移動設(shè)備上尤為明顯。(特殊情況下,比如當(dāng)數(shù)據(jù)在瀏覽器主線程和排版線程之間傳遞產(chǎn)生的瓶頸也會導(dǎo)致不流暢)。某些CSS屬性,比如transform和opacity,則不受這些瓶頸影響。Adobe在這里精心總結(jié)了這些問題。
- transition在IE10以下沒有用,造成的自IE8和IE9以來的桌面站點可用性問題至今仍然廣泛存在。
- 由于transition并不是由JavaScript原生控制(而僅僅是由JavaScript觸發(fā)),瀏覽器無法獲知如何與控制這些transition的JavaScript代碼同步地優(yōu)化他們。
相反的,基于JavaScript的動畫庫則可以自行確定合適開啟硬件。它們原生支持各版本IE瀏覽器,并且它們尤其適合批量動畫優(yōu)化。
我的建議是僅當(dāng)你單獨為移動端開發(fā)且僅實現(xiàn)簡單動畫時使用原生CSS變換。這種環(huán)境下,transition是一種原生有效的解決方案,可以使你在樣式表中實現(xiàn)所有動畫邏輯,而不用添加額外的JavaScript庫,從而避免你的頁面變得臃腫。然而,當(dāng)你在設(shè)計復(fù)雜的UI,或者是開發(fā)存在不同狀態(tài)的UI的App時,你就應(yīng)該使用動畫庫以使動畫保持流暢,同時使工作流程易于管理。Transit是一個在管理CSS變換方面做得尤其優(yōu)秀的庫。
JavaScript 動畫
好了,那JavaScript可就在性能方面占據(jù)上風(fēng)了. 但Javascript究竟具體快了多少呢? 好吧 — 最初 — 對于構(gòu)建一個實在的 3D動畫示例 是足夠快的,通常在構(gòu)建中你只會看到有使用WebGL. 而構(gòu)建一個 多媒體小動畫 也夠了,通常你看到只會使用Flash或者After Effects構(gòu)建. 而構(gòu)建一個 虛擬世界 也夠了,通常你只會看到使用canvas構(gòu)建.
為了對領(lǐng)先的動畫庫,當(dāng)然還要包含Transit(它使用CSS漸變效果),進(jìn)行直接的對比, 回頭去看看Velocity在VelocityJS.org上的文檔.
問題仍然是: JavaScript是怎樣具體的達(dá)成其高水平性能的? 下面是對基于Javascript動畫能夠被執(zhí)行這一目標(biāo)的優(yōu)化的一個簡短清單:
- 同步 DOM → 在整個動畫鏈中間入棧以最小化布局抖動.
- 為整個鏈?zhǔn)秸{(diào)用緩存屬性值,以最小化DOM查詢發(fā)生 (這些就是高性能DOM動畫的坑).
- 在同樣的調(diào)用中緩存整個同級別元素的單元轉(zhuǎn)換率 (比如 px 到 %, em, 等等.).
- 當(dāng)更新可能會在視覺上不可見時跳過樣式更新.
回顧一下我們先前學(xué)過的關(guān)于布局顛簸的知識,Velocity.js利用這些最佳實踐來緩存動畫結(jié)束值以復(fù)用為隨后動畫的開始值,從而避免了重新查詢DOM以獲取元素的開始值:
$element /* Slide the element down into view. */ .velocity({ opacity: 1, top: "50%" }) /* After a delay of 1000ms, slide the element out of view. */ .velocity({ opacity: 0, top: "-50%" }, { delay: 1000 });
在上面例子中,第二個 Velocity 調(diào)用知道它應(yīng)該自動從 opacity為1 和 top為50% 開始。
瀏覽器本身最終能夠執(zhí)行許多這些相同的優(yōu)化,但這樣做會明顯減少開發(fā)者能夠制作的動畫代碼的方式。因此,出于同樣原因,由于jQuery不使用RAF(如上所述),瀏覽器就不會強制優(yōu)化它,甚至給出一個很小的機會去打破規(guī)格或偏離預(yù)期的行為。
最后,我們對這兩個JavaScript動畫庫(Velocity.js 和 GSAP)互相比較一下。
GSAP 是首個動畫庫,用在演示JavaScript DOM 令人印象深刻的動畫表現(xiàn)。它確實是這樣,但有些缺點:
- 在中到高負(fù)荷動畫中,GSAP 的 DOM 交互開銷導(dǎo)致動畫在開始時和過程中失幀。
- 相反于Velocity.js 是在超寬松的 MIT 許可下發(fā)布的, GSAP 是閉源的, 并且在很多類商用時候需要許可年費。
- 因為 GSAP 是一個完整的動畫套件,是 Velocity 大小的三倍。然而,GSAP 有如此豐富功能,有助于其成為動畫的瑞士軍刀。
我推薦做法是在你需要精確控制定時(比如 重繪,暫停/恢復(fù))和運動(比如貝塞爾曲線路徑)的時候用 GSAP 。這些特性在游戲開發(fā)和某些特殊應(yīng)用中是至關(guān)重要的,但是通常不需要用在網(wǎng)頁應(yīng)用的 UI中。
Velocity.js
引用 GSAP 豐富的特性并不代表Velocity自身在特性上是輕量級的. 相反,在壓縮后僅有的7kb中,Velocity不僅僅復(fù)制了jQuery $.animate()的所有功能, 它還把顏色動畫,轉(zhuǎn)換,循環(huán),easing效果,類動畫還有滾動都打包了進(jìn)去.
總之,Velocity是jQuery,jQuery UI,以及CSS漸變效果的最佳組合.
此外,從便利的角度看,Velocity在hood(蓋子,大概意思是公共的接口)之下使用jQuery的 $.queue() 方法, 如此就可以實現(xiàn)同 jQuery 的 $.animate(), $.fade(), 和 $.delay() 函數(shù)的無縫互操作. 而且,由于Velocity的語法同 $.animate() 的語法是相同的, 你不需要改變頁面的任何代碼.
讓我們快速地來看一看 Velocity.js. 在基礎(chǔ)的層面,Velocity的行為同$.animate()一樣:
$element .delay(1000) /* Use Velocity to animate the element's top property over a duration of 2000ms. */ .velocity({ top: "50%" }, 2000) /* Use a standard jQuery method to fade the element out once Velocity is done animating top. */ .fadeOut(1000);
在其最高級的層面,可以創(chuàng)建帶有3D動畫的復(fù)雜滾動場景 — 幾乎只要用到兩行簡單的代碼:
$element /* Scroll the browser to the top of this element over a duration of 1000ms. */ .velocity("scroll", 1000) /* Then rotate the element around its Y axis by 360 degrees. */ .velocity({ rotateY: "360deg" }, 1000);
相關(guān)文章
解決layui table表單提示數(shù)據(jù)接口請求異常的問題
今天小編就為大家分享一篇解決layui table表單提示數(shù)據(jù)接口請求異常的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09