亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 語言 > JavaScript > 正文

使用requestAnimationFrame實現js動畫性能好

2024-05-06 16:24:24
字體:
來源:轉載
供稿:網友

requestAnimationFrame優于setTimeout/setInterval的地方在于它是由瀏覽器專門為動畫提供的API,在運行時瀏覽器會自動優化方法的調用,并且如果頁面不是激活狀態下的話,動畫會自動暫停,有效節省了CPU開銷,這篇文章給大家詳細介紹使用requestAnimationFrame實現js動畫

使用requestAnimationFrame實現js動畫性能好。先給大家簡單介紹下requestAnimationFrame比起setTimeout、setInterval有哪些優勢?

示例一:

requestAnimationFrame 比起 setTimeout、setInterval的優勢主要有兩點:

1、requestAnimationFrame 會把每一幀中的所有DOM操作集中起來,在一次重繪或回流中就完成,并且重繪或回流的時間間隔緊緊跟隨瀏覽器的刷新頻率,一般來說,這個頻率為每秒60幀。

2、在隱藏或不可見的元素中,requestAnimationFrame將不會進行重繪或回流,這當然就意味著更少的的cpu,gpu和內存使用量。

像setTimeout、setInterval一樣,requestAnimationFrame是一個全局函數。調用requestAnimationFrame后,它會要求瀏覽器根據自己的頻率進行一次重繪,它接收一個回調函數作為參數,在即將開始的瀏覽器重繪時,會調用這個函數,并會給這個函數傳入調用回調函數時的時間作為參數。由于requestAnimationFrame的功效只是一次性的,所以若想達到動畫效果,則必須連續不斷的調用requestAnimationFrame,就像我們使用setTimeout來實現動畫所做的那樣。requestAnimationFrame函數會返回一個資源標識符,可以把它作為參數傳入cancelAnimationFrame函數來取消requestAnimationFrame的回調。怎么樣,是不是也跟setTimeout的clearTimeout很相似啊。

所以,可以這么說,requestAnimationFrame就是一個性能優化版、專為動畫量身打造的setTimeout,不同的是requestAnimationFrame不是自己指定回調函數運行的時間,而是跟著瀏覽器內建的刷新頻率來執行回調,這當然就能達到瀏覽器所能實現動畫的最佳效果了。

目前,各個支持requestAnimationFrame的瀏覽器有些還是自己的私有實現,所以必須加前綴,對于不支持requestAnimationFrame的瀏覽器,我們只能使用setTimeout,因為兩者的使用方式幾近相同,所以這兩者的兼容并不難。對于支持requestAnimationFrame的瀏覽器,我們使用requestAnimationFrame,而不支持的我們優雅降級使用傳統的setTimeout。把它們封裝一下,就能得到一個統一兼容各大瀏覽器的API了。

代碼可以到這里來查看:https://gist.github.com/chaping/88813f56e75b0fd43f8c

 

 
  1. var lastTime = 0; 
  2. var prefixes = 'webkit moz ms o'.split(' '); //各瀏覽器前綴 
  3. var requestAnimationFrame = window.requestAnimationFrame; 
  4. var cancelAnimationFrame = window.cancelAnimationFrame; 
  5. var prefix; 
  6. //通過遍歷各瀏覽器前綴,來得到requestAnimationFrame和cancelAnimationFrame在當前瀏覽器的實現形式 
  7. forvar i = 0; i < prefixes.length; i++ ) { 
  8. if ( requestAnimationFrame && cancelAnimationFrame ) { 
  9. break
  10. prefix = prefixes[i]; 
  11. requestAnimationFrame = requestAnimationFrame || window[ prefix + 'RequestAnimationFrame' ]; 
  12. cancelAnimationFrame = cancelAnimationFrame || window[ prefix + 'CancelAnimationFrame' ] || window[ prefix + 'CancelRequestAnimationFrame' ]; 
  13. //如果當前瀏覽器不支持requestAnimationFrame和cancelAnimationFrame,則會退到setTimeout 
  14. if ( !requestAnimationFrame || !cancelAnimationFrame ) { 
  15. requestAnimationFrame = function( callback, element ) { 
  16. var currTime = new Date().getTime(); 
  17. //為了使setTimteout的盡可能的接近每秒60幀的效果 
  18. var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );  
  19. var id = window.setTimeout( function() { 
  20. callback( currTime + timeToCall ); 
  21. }, timeToCall ); 
  22. lastTime = currTime + timeToCall; 
  23. return id; 
  24. }; 
  25. cancelAnimationFrame = function( id ) { 
  26. window.clearTimeout( id ); 
  27. }; 
  28. //得到兼容各瀏覽器的API 
  29. window.requestAnimationFrame = requestAnimationFrame;  
  30. window.cancelAnimationFrame = cancelAnimationFrame; 

這樣子我們就能在所有瀏覽器上使用requestAnimationFrame和cancelAnimationFrame了。

下面舉個簡單的例子來說明怎么運用requestAnimationFrame進行動畫,下面的代碼會將id為demo的div以動畫的形式向右移動到300px

 

 
  1. <div id="demo" style="position:absolute; width:100px; height:100px; background:#ccc; left:0; top:0;"></div> 
  2. <script> 
  3. var demo = document.getElementById('demo'); 
  4. function rander(){ 
  5. demo.style.left = parseInt(demo.style.left) + 1 + 'px'//每一幀向右移動1px 
  6. requestAnimationFrame(function(){ 
  7. rander(); 
  8. //當超過300px后才停止 
  9. if(parseInt(demo.style.left)<=300) requestAnimationFrame(arguments.callee); 
  10. }); 
  11. </script> 

示例二:

一直以來,JavaScript的動畫都是通過定時器和間隔來實現的。雖然使用CSS transitions 和 animations使Web開發實現動畫更加方便,但多年來以JavaScript為基礎來實現動畫卻很少有所改變。直到Firefox 4的發布,才帶來了第一種對JavaScript動畫的改善的方法。但要充分認識改善,這有利于幫助我們了解web動畫是如何演變改進的。

定時器Timer

用于創建動畫的第一個模式是使用鏈式setTimeout()調用。在Netscape 3′s hayday的很長一段時期,開發者都記得一種在網絡上隨處可見的固定式最新行情狀態欄,通常它類似于這樣:

 

 
  1. (function(){  
  2. var msg = "新的廣告",  
  3. len = 25,  
  4. pos = 0,  
  5. padding = msg.replace(/./g, " ").substr(0,len),  
  6. finalMsg = padding + msg;  
  7. function updateText(){  
  8. var curMsg = finalMsg.substr(pos++, len);  
  9. window.status = curMsg;  
  10. if (pos == finalMsg.length){ pos = 0; }  
  11. setTimeout(updateText, 100);  
  12. }  
  13. setTimeout(updateText, 100);  
  14. })();  

如果你想在瀏覽器中測試這段代碼,你可以新建一個

標簽用來模擬window.status,例如:newsticker example

這種讓人煩惱的web模式,后來遭到對window.status禁用的抵抗,但隨著Explorer 4和Netscape 4的發布,瀏覽器第一次給開發者更多對頁面元素的控制權限,這種技術再次出現。這樣就出現了使用javascript動態改變元素大小、位置、顏色等的一種全新動畫模式。例如,下面就是一個將div寬度變化成100%的動畫(類似于進度條):

 

 
  1. (function(){  
  2. function updateProgress(){  
  3. var div = document.getElementByIdx_x("status");  
  4. div.style.width = (parseInt(div.style.width, 10) + 5) + "%";  
  5. if (div.style.width != "100%"){ setTimeout(updateProgress, 100); }  
  6. }  
  7. setTimeout(updateProgress, 100);  
  8. })();  

盡管動畫在頁面上的地方不同,但基本原理卻是一樣的:做出改變,用setTimeout()間隔使頁面更新,然后setTimeout又執行下一次變化,這個過程反復執行,直到動畫完成(見進度條動畫),早期的狀態欄動畫是相同的技術,只是動畫不一樣而已。

間隔動畫Intervals

隨著成功將動畫引入web,新的探索開始了。一個動畫已經無法滿足了,現在需要多個動畫。首次嘗試為每個動畫創建多個動畫循環,在早期的瀏覽器中使用setTimeout()來創建多個動畫是有點復雜的,所以開發商開始使用setInterval()一創建單一的動畫循環,來管理頁面上所有的動畫,一個使用wetInterval()的基本動畫像這樣:

 

 
  1. (function(){  
  2. function updateAnimations(){  
  3. updateText();  
  4. updateProgress();  
  5. }  
  6. setInterval(updateAnimations, 100);  
  7. })(); 

創建一個小動畫庫,updateAnimations()方法將每一個動畫(同時看到一個新聞股票和進度條在一起運行)循環執行并進行適當的改變。如果沒有動畫需要更新,該方法可以退出而不做任何事情,甚至停止動畫循環,直到有更多的動畫更新做好準備。

動畫問題比較棘手的問題是延遲應該為多少。間隔一方面必須足夠短,從而使不同的動畫都能流暢的進行,別一方面還要足夠長,使得瀏覽器可以完成渲染。大多數瀏覽器的刷新頻率為60HZ,即每秒60次刷新,大多數瀏覽器的刷新頻率都不會比這個更頻繁,因為他們知道,最終用戶是得不到更好的體驗的。

鑒于此,為流暢動畫的最佳時間間隔為1000毫秒/ 60,約17ms。在這個頻率你會看到流暢的動畫,那是因為你最大的接近了瀏覽器能達到的頻率。跟以前的動畫相比,你會發現17ms間隔的動畫更加平滑,也更快(因為動畫更新更頻繁,沒有做其他任何修改的情況下),多個動畫可能需要節流,以免17ms的動畫完成得太快。

問題

即使使用setInterval()為基礎的動畫循環比多套使用setTimeout()的動畫循環高效,這里還是存在問題。無論是setInterval()還是setTimeout()都無法達到精確,這個延遲即你指定的第二個參數僅僅表示何時代碼會添加到瀏覽器的可能被執行的UI線程隊列中。如果隊列中有其他工作在此之前,那代碼將會等到他完成才會執行。簡而言之,毫秒級的延遲不是表示何時代碼會執行,而是表示何時代碼會添加進隊列。如果UI線程處于繁忙狀態或在處理用戶動作,那么代碼將不會被馬上執行。

平滑動畫的關鍵是理解下一幀何時被執行,直到現在都沒有一個方法來保證下一幀將會在瀏覽器中被繪制。隨著的日益流行和新的基于瀏覽器的游戲的出現,開發商對setInterval()和setTimeout()的不精準越來越感到失望。

瀏覽器的計時器分辨率加劇了這個問題,計時器對毫秒不精準,這里有一些常見的計時器分辨率:

Internet Explorer 8 and earlier 15.625ms Internet Explorer 9 and later 4ms. Firefox and Safari ~10ms. Chrome has a timer 4ms.

IE在版本9之前的的分辨率為15.625,所以0~15之間的任意值可能是0或15,但沒有分別。IE9的計時器分辨率改進為4ms,但涉及到動畫時也是不具體的,chrome的計時器分辨率為4ms,firefox 和 safari的為10ms。因此即使你把間隔設定為最佳的顯示效果,你也僅僅是得到這個近似值。

mozRequestAnimationFrame

Mozilla 的 Robert O'Callahan 在思考這個問題,并想出了一個獨特的方案。他指出CSS transitions 和 animations的優勢在于瀏覽器知道哪些動畫將會發生,所以得到正確的間隔來刷新UI。而javascript動畫,瀏覽器不知道動畫正在發生。他的解決方案是創建一個mozRequestAnimationFrame()方法來告訴瀏覽器哪些javascript代碼正在執行,這使得瀏覽在執行一些代碼后得到優化。

mozRequestAnimationFrame()方法接受一個參數,是一個屏幕重繪前被調用的函數。這個函數用來對生成下合適的dom樣式的改變,這些改變用在下一次重繪中。你可以像調用setTimeout()一樣的方式鏈式調用mozRequestAnimationFrame(),例如:

 

 
  1. function updateProgress(){  
  2. var div = document.getElementByIdx_x("status");  
  3. div.style.width = (parseInt(div.style.width, 10) + 5) + "%";  
  4. if (div.style.left != "100%"){  
  5. mozRequestAnimationFrame(updateProgress);  
  6. }  

mozRequestAnimationFrame(updateProgress);

由于mozRequestAnimationFrame()只運行給定的函數一次,你需要在下一次UI動畫的時候再次調用它。你也需要相同的方法來管理何時停止調用。很酷,是非常流暢的動畫增強的實例。

因此,mozRequestAnimationFrame()解決了瀏覽器不知道Javascript動畫正在執行和不知道多少才是合適的間隔的問題,但對于不知道何時你的代碼才被真正執行,也是由這個方案來解決的。

傳遞給mozRequestAnimationFrame()的函數實際是一個下一次重繪何時發生的的時間碼(以毫秒為單位自1970年1月1日計算)。這是很重要的一點:mozRequestAnimationFrame()實際上列表出將要重繪的點并可以告訴你他們所處的時間。這樣你就能夠決定怎樣更好的來調整你的動畫。

為了得到上次重繪過去的時間,你可以查詢mozAnimationStartTime,其中包含了過去重繪的時間代碼。減去傳遞回調時的這個值可以計算出下一次重繪到屏幕時所用的時間。使用這些值的典型模式如下:

 

 
  1. function draw(timestamp){  
  2. //calculate difference since last repaint  
  3. var diff = timestamp - startTime;  
  4. //use diff to determine correct next step  
  5. //reset startTime to this repaint  
  6. startTime = timestamp;  
  7. //draw again  
  8. mozRequestAnimationFrame(draw);  
  9. }  
  10. var startTime = mozAnimationStartTime;  
  11. mozRequestAnimationFrame(draw);  

關鍵是第一次不是通過callback調用時,mozAnimationStartTime是到mozRequestAnimationFrame()經過的時間。如果是在回調函數中,mozAnimationStartTime是通過參數傳遞進來的時間代碼平均值。

webkitRequestAnimationFrame

在很多人熱忠于chrome時,隨即創建了webkitRequestAnimationFrame()方法。這個版本與firefox的版本在兩方面有著細微的差別。一方面,它不通過回調函數傳遞時間代碼,你將無法知道下次重繪何時發生,另一方面,它添加了第二個可選參數來確定哪一個DOM元素發生改變。因此,如果你知道重繪發生在頁面哪個部分的元素內,你可以限制重繪發生的區域。

應該不會感到驚訝,有沒有相應的mozAnimationStartTime,因為如果沒有下一個重繪的時間信息不是很有益。有,只是webkitCancelAnimationFrame()取消了之前計劃的重繪。

如果你不需要精確的時間差異,你可以用下面的方式來創建一個用于Firefox4和chrome10+的動畫:

 

  1. function draw(timestamp){  
  2. //calculate difference since last repaint  
  3. var drawStart = (timestamp || Date.now()),  
  4. diff = drawStart - startTime;  
  5. //use diff to determine correct next step  
  6. //reset startTime to this repaint  
  7. startTime = drawStart;  
  8. //draw again  
  9. requestAnimationFrame(draw);  
  10. }  
  11. var requestAnimationFrame = window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame,  
  12. startTime = window.mozAnimationStartTime || Date.now();  
  13. requestAnimationFrame(draw);  

這種模式使用可用的方法來創建以花費多少時間為理念的循環動畫。Firefox使用時間代碼信息是有用的,而Chrome默認為欠精準的時間對象。當用這種模式的時候,時間的差異給你一種多少時間過去了的想法,但不會告訴你Chrome的下一次重繪出現在何時。不過這比只有多少時間過去了的模糊概念要好些。

總結

mozRequestAnimationFrame()方法的介紹為推動Javascript 動畫及web的歷史發展有著非常重要的作用。如前所述,JavaScript動畫的態幾乎和JavaScript的初期一樣。隨著瀏覽器逐漸推出CSS transitions 和 animations,很高興看到基于JavaScript的動畫的關注,因為這些在基于的游戲領域將變得更重要和更與CUP聯系緊密。知道Javascript何時嘗試動畫,允許瀏覽器做更多的優化處理,包括在tab處于后臺或移動設備電量過低時停止進程。

該requestAnimationFrame()API現在正由W3C起草一個新議案,并正由Mozilla和Google努力使之成為Web大舞臺的一部分。很高興能看到這兩大集團這么迅速的兼容(可能不完全)實現。

RequestAnimFrame使用

對于一個偵中對DOM的所有操作,只進行一次Layout和Paint。

如果發生動畫的元素被隱藏了,那么就不再去Paint。

 

 
  1. window.requestAnimFrame = (function(){  
  2. return window.requestAnimationFrame ||  
  3. window.webkitRequestAnimationFrame ||  
  4. window.mozRequestAnimationFrame ||  
  5. window.oRequestAnimationFrame ||  
  6. window.msRequestAnimationFrame ||  
  7. function( callback ){  
  8. window.setTimeout(callback, 1000/60);  
  9. };  
  10. })();  
  11. //調用  
  12. function animationLoop(elem){  
  13. requestAnimFrame(animationLoop);  
  14. //logic  
  15. }  
  16. Or 
  17. window.requestAnimFrame = (function(w, r) {  
  18. w['r'+r] = w['r'+r] || w['webkitR'+r] || w['mozR'+r] || w['msR'+r] || w['oR'+r] || function(c){ w.setTimeout(c, 1000 / 60); };  
  19. return w['r'+r];  
  20. })(window, 'equestAnimationFrame');  

以上通過兩段代碼示例詳解說明了使用requestAnimationFrame實現js動畫性能好,希望大家喜歡。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产福利精品av综合导导航| 国产男女猛烈无遮挡91| 亚洲自拍小视频| 欧美精品一区二区三区国产精品| 日本久久久久久久久久久| 8x海外华人永久免费日韩内陆视频| 精品中文字幕视频| 国内精品中文字幕| 中文字幕成人精品久久不卡| 亚洲成人av在线| 欧美激情二区三区| 欧美又大又硬又粗bbbbb| 色悠久久久久综合先锋影音下载| 国产精品久久久久影院日本| 2019日本中文字幕| 在线日韩av观看| 亚洲一区亚洲二区亚洲三区| 国产精品视频网| 青青青国产精品一区二区| 成人国产精品久久久久久亚洲| 欧美精品www| 欧美制服第一页| 亚洲视频在线免费看| 亚洲欧美www| 国产精品18久久久久久首页狼| 亚洲成人久久网| 亚洲国产欧美日韩精品| 欧美日韩国产色视频| 成人精品一区二区三区| 国产精品福利无圣光在线一区| 欧美成人精品不卡视频在线观看| 欧美一区二区三区图| 久久精品国产99国产精品澳门| 红桃视频成人在线观看| 欧美激情国产高清| 成人春色激情网| 神马久久桃色视频| 69视频在线免费观看| 国产精品视频一区国模私拍| 国产精品久久久久一区二区| 日本中文字幕久久看| 欧美国产日韩二区| 日韩国产精品一区| 日韩av理论片| 最近2019中文字幕mv免费看| 亚洲视频电影图片偷拍一区| 久久久亚洲精品视频| 亚洲精品第一国产综合精品| 美女少妇精品视频| 97国产真实伦对白精彩视频8| 欧美主播福利视频| 日韩视频免费大全中文字幕| 亚洲日本欧美日韩高观看| 亚洲免费精彩视频| 国产精品一香蕉国产线看观看| 在线播放日韩专区| 久久成人在线视频| 亚洲精品第一国产综合精品| www.国产一区| 国产伦精品一区二区三区精品视频| 久久久免费观看| 精品久久久久久亚洲精品| 国产综合在线看| 久久久视频免费观看| 欧美激情三级免费| 性色av一区二区咪爱| 国产精品久久久久久久久久新婚| 日韩久久免费电影| 国产精品老牛影院在线观看| 精品福利免费观看| 精品日本美女福利在线观看| 午夜精品美女自拍福到在线| 91精品国产色综合久久不卡98口| 91久久精品国产91性色| 久久久女女女女999久久| 久久影视三级福利片| 久久久久国产精品免费网站| 亚洲xxxxx| 亚洲wwwav| 亚洲国产精品成人精品| 国产精品视频资源| 91精品国产乱码久久久久久久久| 久久99视频免费| 欧美噜噜久久久xxx| 最新的欧美黄色| 久久免费成人精品视频| 亚洲精品自拍偷拍| 欧美xxxx做受欧美.88| 日韩中文字幕久久| 超碰97人人做人人爱少妇| 亚洲精品自拍视频| 欧美一乱一性一交一视频| 欧美专区国产专区| 日本久久91av| 欧美日韩国产综合视频在线观看中文| 日韩成人激情影院| 久久成人18免费网站| 亚洲天堂一区二区三区| 亚洲欧美综合精品久久成人| 欧美在线视频一二三| 成人中文字幕+乱码+中文字幕| 精品久久香蕉国产线看观看亚洲| 免费99精品国产自在在线| 中文字幕最新精品| 91网在线免费观看| 日韩国产在线播放| 国语自产精品视频在线看一大j8| 亚洲一区亚洲二区亚洲三区| 欧美激情2020午夜免费观看| 久久琪琪电影院| 亚洲另类xxxx| 亚洲第一av网站| 日韩69视频在线观看| 亚洲国产精品专区久久| 亚洲高清av在线| 欧美日韩福利在线观看| 亚洲色图美腿丝袜| 国产日韩中文字幕在线| 久久人人97超碰精品888| 亚洲黄一区二区| 国产精品狼人色视频一区| 九九热这里只有在线精品视| 国产精品第一区| 热门国产精品亚洲第一区在线| 国产精品精品视频一区二区三区| 亚洲成人av中文字幕| 日韩精品在线视频观看| 久久精品影视伊人网| 久久夜色精品国产欧美乱| 日韩精品中文字幕在线| 亚洲成人性视频| 国产91色在线|免| 91夜夜揉人人捏人人添红杏| 最近的2019中文字幕免费一页| 国产欧美欧洲在线观看| 亚洲综合日韩在线| 精品国内亚洲在观看18黄| 国产精品露脸av在线| 亚洲va久久久噜噜噜久久天堂| 亚洲第一精品久久忘忧草社区| 亚洲成人精品视频在线观看| 久久久伊人欧美| 日韩精品免费观看| 91免费人成网站在线观看18| 久久精品小视频| 成人在线视频福利| 中文字幕亚洲欧美日韩在线不卡| 3344国产精品免费看| 国产日产久久高清欧美一区| 日韩精品在线播放| 欧美黑人一级爽快片淫片高清| 91精品国产自产在线老师啪| 高清亚洲成在人网站天堂| 国产欧美亚洲精品| 久久躁狠狠躁夜夜爽| 日韩风俗一区 二区| 成人午夜在线观看| 国产色婷婷国产综合在线理论片a| 欧美成人免费在线视频| 亚洲娇小xxxx欧美娇小| 亚洲激情小视频| 国产成人精品优优av| 亚洲国产私拍精品国模在线观看| 黑人巨大精品欧美一区二区三区|