动画性能优化-requestAnimationFrame、GPU等
生活随笔
收集整理的這篇文章主要介紹了
动画性能优化-requestAnimationFrame、GPU等
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最近在做一個場景動畫,有一個歡迎界面和一個主動畫界面,兩個界面之間的連接通過一個進度條來完成,當進度條完成,提供通往主動畫的按鈕。 畫面會從一個個的場景移動過去,用戶可通過點擊抽獎、查看氣泡商鋪等進行交互,同時可拖動畫面,前移或后退。該項目中,出了主動畫,還有人物場景對話的動畫等,性能的優化、用戶的體驗變得尤為重要,這里總結一下在開發過程中使用的一些性能、體驗優化方法。? 1、動畫
a、優先采用requestanimationframe,實現動畫幀的并發渲染;
b、做減法:兼容低版本瀏覽器(a中的元素不生效,通過setTimeout實現動畫),保留主動畫性能,去除重要性不大的動畫(跑馬燈、過程小動畫等);
c、大圖動畫性能消耗非常大,使用translate3d實現GPU加速,動畫結束、暫停時,切換回2d,取消加速;
d、按需加載/卸載動畫; e、每個動畫幀處理函數簡化,盡量減少或者去除回流、重繪。 2、加載、用戶體驗優化
a、首屏優先加載,保證用戶體驗的流暢性:優先歡迎界面(即首屏)圖片資源的加載,所有圖片loaded以后,再啟動主動畫資源的加載,與進度條動畫;
b、資源的預加載:在進入主動畫之前,進行主動畫各資源的加載,當完成加載時,再promise結束進度條動畫;? c、常規優化:雪碧圖、壓縮、base64等; d、存儲dom變量,減少dom tree的查找等;
e、限頻。
3、說明 3.1、requestAnimationFrame 它是一種高級的方法,存在兼容性問題。主要運作方式是瀏覽器要進行繪制的時候(一般16.7ms一次繪制),會通知requestAnimationFrame們,requestAnimationFrame們就跟它一起繪制。這里有幾個好處,多個requestAnimationFrame可以同時進行,而setTimeout需要獨立繪制;頁面切換等情況,瀏覽器不再繪制該頁面,requestAnimationFrame也停止了繪制,與瀏覽器同步,資源很省。相對setTimeout,是一個js的執行棧,只能串行執行,并且會影響其他js的處理。所以,使用前者,性能更佳,更流暢,交互體驗更佳。特別是多個動畫同時進行時,前者毫無壓力,后者表示卡頓厲害。兼容代碼如下,引自張鑫旭的log,感興趣的同學可以仔細讀一下:鏈接 1 /* requestAnimationFrame.js 2 * by zhangxinxu 2013-09-30 3 */ 4 (function() { 5 var lastTime = 0; 6 var vendors = ['webkit', 'moz']; 7 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 8 window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; 9 window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || // name has changed in Webkit 10 window[vendors[x] + 'CancelRequestAnimationFrame']; 11 } 12 13 if (!window.requestAnimationFrame) { 14 window.requestAnimationFrame = function(callback) { 15 var currTime = new Date().getTime(); 16 var timeToCall = Math.max(0, 16.7 - (currTime - lastTime)); 17 var id = window.setTimeout(function() { 18 callback(currTime + timeToCall); 19 }, timeToCall); 20 lastTime = currTime + timeToCall; 21 return id; 22 }; 23 } 24 if (!window.cancelAnimationFrame) { 25 window.cancelAnimationFrame = function(id) { 26 clearTimeout(id); 27 }; 28 } 29 }()); 3.2、項目中的減法 這種要做減法的情況下,最佳的體驗是自己把動畫都完成好,直接演示給產品、設計童鞋看,他們就能從中取舍了,沒有任何的扯皮、分歧。tips:當然動畫不需要跟實際用的一致,幾個特性差不多就好,比如主動畫背景圖非常大,多個動畫并行,且持續時間比較長。 3.3、關于大圖動畫 這種動畫渲染的性能消耗往往非常大,考慮開啟GPU來加速圖層的渲染,但是由于GPU的渲染又是非常耗費內存、電量的,所以在不需要移動的情況下,需要關閉GPU,防止瀏覽器的崩潰。在該項目中,當用戶進行游戲交互等,觸發主動畫暫停時,將通過設置translate2d,取消加速;啟動時,再開啟。 3.4、按需加載/卸載動畫 對于場景動畫來說,有些動效,只有出現在視口時,才有播放的必要性;離開視口,就可以關閉。通過判斷動畫當前的位置,可以實現動畫的按需加載。 3.5、重繪、回流 動畫幀內減少處理,即避免長時間的js執行;減少回流、重繪在哪里都適用,可以用transform等操作,來替代position;left等等的操作。當需要display:none的情況下(回流),使用opacity:0(重繪);或者visibility:hidden(重繪),將更優。回流的性能消耗要遠大于重繪。 3.6、首屏優先加載 在網速很可觀的情況下,完全可以同時加載整站的資源,僅將首屏的資源前置即可。 但在網絡狀況很抓狂的情況下(如3g下),這種大量圖片、音頻的頁面,就需要考慮資源分批啟動加載的必要性了。在網速欠佳,但是服務器允許多并發的情況下,同時可以請求多個資源,此時帶寬及其有限的,雖然整體的加載時間沒變化,但是首屏的加載時間卻延長了。如當前帶寬時750kb/s,10個資源一起請求,則每個分到75kb/s,150kb的圖片,需要加載2s;如果只有3個資源一起請求,分到250kb/s,需加載0.6s。因此,為了體驗更佳,首屏的資源加載完畢,再開啟主動畫資源加載。 3.7、資源的預加載 因為主動畫中的交互、資源較多,需要資源穩定以后才能有更好的用戶體驗,所以這里提供了資源的預加載。 圖片預加載: newImgObjs[i] = new Image(); newImgObjs[i].src = animationImgs[i];newImgObjs[i].onload = function() {loadeds++;if (loadeds == newImgObjs.length) {self.barObj.completeWelcomePromise.resolve();console.log('圖片資源已經加載完成');} };newImgObjs[i].onerror = function() {loadeds++;if (loadeds == newImgObjs.length) {self.barObj.completeWelcomePromise.resolve();console.log('圖片資源已經加載完成');} }; 音頻預加載: $audio[0].src = imgPath; $audio.on('canplaythrough', function() {loadeds++;if (loadeds == (newImgObjs.length + 1)) {self.barObj.completePromise.resolve();console.log('音頻資源已經加載完成');} });$audio[0].onerror = function(e) {loadeds++;if (loadeds == (newImgObjs.length + 1)) {self.barObj.completePromise.resolve();console.log('音頻資源已經加載完成');} }; 3.8、其他幾種 限頻、dom操作、雪碧圖等不再多說。關于響應式下的雪碧圖處理,上一篇博客有提供系統的解決方案。 4、promise的使用 在該項目中,promise的使用較為頻繁,包括ajax請求、圖片的預加載、進度條的處理等。 // 資源處理:預加載、監控加載完成、渲染 $.when(self.cmsInfoPromise, self.goodsInfoPromise, self.barObj.completeWelcomePromise).done(function() {// 進度條動效 self.barAnimation();self.handleResource();self.renderStores();});
a、優先采用requestanimationframe,實現動畫幀的并發渲染;
b、做減法:兼容低版本瀏覽器(a中的元素不生效,通過setTimeout實現動畫),保留主動畫性能,去除重要性不大的動畫(跑馬燈、過程小動畫等);
c、大圖動畫性能消耗非常大,使用translate3d實現GPU加速,動畫結束、暫停時,切換回2d,取消加速;
d、按需加載/卸載動畫; e、每個動畫幀處理函數簡化,盡量減少或者去除回流、重繪。 2、加載、用戶體驗優化
a、首屏優先加載,保證用戶體驗的流暢性:優先歡迎界面(即首屏)圖片資源的加載,所有圖片loaded以后,再啟動主動畫資源的加載,與進度條動畫;
b、資源的預加載:在進入主動畫之前,進行主動畫各資源的加載,當完成加載時,再promise結束進度條動畫;? c、常規優化:雪碧圖、壓縮、base64等; d、存儲dom變量,減少dom tree的查找等;
e、限頻。
3、說明 3.1、requestAnimationFrame 它是一種高級的方法,存在兼容性問題。主要運作方式是瀏覽器要進行繪制的時候(一般16.7ms一次繪制),會通知requestAnimationFrame們,requestAnimationFrame們就跟它一起繪制。這里有幾個好處,多個requestAnimationFrame可以同時進行,而setTimeout需要獨立繪制;頁面切換等情況,瀏覽器不再繪制該頁面,requestAnimationFrame也停止了繪制,與瀏覽器同步,資源很省。相對setTimeout,是一個js的執行棧,只能串行執行,并且會影響其他js的處理。所以,使用前者,性能更佳,更流暢,交互體驗更佳。特別是多個動畫同時進行時,前者毫無壓力,后者表示卡頓厲害。兼容代碼如下,引自張鑫旭的log,感興趣的同學可以仔細讀一下:鏈接 1 /* requestAnimationFrame.js 2 * by zhangxinxu 2013-09-30 3 */ 4 (function() { 5 var lastTime = 0; 6 var vendors = ['webkit', 'moz']; 7 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 8 window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; 9 window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || // name has changed in Webkit 10 window[vendors[x] + 'CancelRequestAnimationFrame']; 11 } 12 13 if (!window.requestAnimationFrame) { 14 window.requestAnimationFrame = function(callback) { 15 var currTime = new Date().getTime(); 16 var timeToCall = Math.max(0, 16.7 - (currTime - lastTime)); 17 var id = window.setTimeout(function() { 18 callback(currTime + timeToCall); 19 }, timeToCall); 20 lastTime = currTime + timeToCall; 21 return id; 22 }; 23 } 24 if (!window.cancelAnimationFrame) { 25 window.cancelAnimationFrame = function(id) { 26 clearTimeout(id); 27 }; 28 } 29 }()); 3.2、項目中的減法 這種要做減法的情況下,最佳的體驗是自己把動畫都完成好,直接演示給產品、設計童鞋看,他們就能從中取舍了,沒有任何的扯皮、分歧。tips:當然動畫不需要跟實際用的一致,幾個特性差不多就好,比如主動畫背景圖非常大,多個動畫并行,且持續時間比較長。 3.3、關于大圖動畫 這種動畫渲染的性能消耗往往非常大,考慮開啟GPU來加速圖層的渲染,但是由于GPU的渲染又是非常耗費內存、電量的,所以在不需要移動的情況下,需要關閉GPU,防止瀏覽器的崩潰。在該項目中,當用戶進行游戲交互等,觸發主動畫暫停時,將通過設置translate2d,取消加速;啟動時,再開啟。 3.4、按需加載/卸載動畫 對于場景動畫來說,有些動效,只有出現在視口時,才有播放的必要性;離開視口,就可以關閉。通過判斷動畫當前的位置,可以實現動畫的按需加載。 3.5、重繪、回流 動畫幀內減少處理,即避免長時間的js執行;減少回流、重繪在哪里都適用,可以用transform等操作,來替代position;left等等的操作。當需要display:none的情況下(回流),使用opacity:0(重繪);或者visibility:hidden(重繪),將更優。回流的性能消耗要遠大于重繪。 3.6、首屏優先加載 在網速很可觀的情況下,完全可以同時加載整站的資源,僅將首屏的資源前置即可。 但在網絡狀況很抓狂的情況下(如3g下),這種大量圖片、音頻的頁面,就需要考慮資源分批啟動加載的必要性了。在網速欠佳,但是服務器允許多并發的情況下,同時可以請求多個資源,此時帶寬及其有限的,雖然整體的加載時間沒變化,但是首屏的加載時間卻延長了。如當前帶寬時750kb/s,10個資源一起請求,則每個分到75kb/s,150kb的圖片,需要加載2s;如果只有3個資源一起請求,分到250kb/s,需加載0.6s。因此,為了體驗更佳,首屏的資源加載完畢,再開啟主動畫資源加載。 3.7、資源的預加載 因為主動畫中的交互、資源較多,需要資源穩定以后才能有更好的用戶體驗,所以這里提供了資源的預加載。 圖片預加載: newImgObjs[i] = new Image(); newImgObjs[i].src = animationImgs[i];newImgObjs[i].onload = function() {loadeds++;if (loadeds == newImgObjs.length) {self.barObj.completeWelcomePromise.resolve();console.log('圖片資源已經加載完成');} };newImgObjs[i].onerror = function() {loadeds++;if (loadeds == newImgObjs.length) {self.barObj.completeWelcomePromise.resolve();console.log('圖片資源已經加載完成');} }; 音頻預加載: $audio[0].src = imgPath; $audio.on('canplaythrough', function() {loadeds++;if (loadeds == (newImgObjs.length + 1)) {self.barObj.completePromise.resolve();console.log('音頻資源已經加載完成');} });$audio[0].onerror = function(e) {loadeds++;if (loadeds == (newImgObjs.length + 1)) {self.barObj.completePromise.resolve();console.log('音頻資源已經加載完成');} }; 3.8、其他幾種 限頻、dom操作、雪碧圖等不再多說。關于響應式下的雪碧圖處理,上一篇博客有提供系統的解決方案。 4、promise的使用 在該項目中,promise的使用較為頻繁,包括ajax請求、圖片的預加載、進度條的處理等。 // 資源處理:預加載、監控加載完成、渲染 $.when(self.cmsInfoPromise, self.goodsInfoPromise, self.barObj.completeWelcomePromise).done(function() {// 進度條動效 self.barAnimation();self.handleResource();self.renderStores();});
?
轉載于:https://www.cnblogs.com/hity-tt/p/6420749.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的动画性能优化-requestAnimationFrame、GPU等的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: openstack--1--基础环境搭建
- 下一篇: WPF 绑定以基础数据类型为集合的无字段