JS-requestAnimationFrame
来源:互联网 发布:unity 特效贴图优化 编辑:程序博客网 时间:2024/04/30 14:35
用js来实现动画,我们一般是借助setTimeout或setInterval这两个函数,css3动画出来后,我们又可以使用css3来实现动画了,而且性能和流畅度也得到了很大的提升。但是css3动画还是有不少局限性,比如不是所有属性都能参与动画、动画缓动效果太少、无法完全控制动画过程等等。所以有的时候我们还是不得不使用setTimeout或setInterval的方式来实现动画,可是setTimeout和setInterval有着严重的性能问题,虽然某些现代浏览器对这两函个数进行了一些优化,但还是无法跟css3的动画性能相提并论。这个时候,就该requestAnimationFrame出马了。
requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个API,目前已在多个浏览器得到了支持,包括IE10+,Firefox,Chrome,Safari,Opera等,在移动设备上,ios6以上版本以及IE mobile 10以上也支持requestAnimationFrame,唯一比较遗憾的是目前安卓上的原生浏览器并不支持requestAnimationFrame,不过对requestAnimationFrame的支持应该是大势所趋了,安卓版本的chrome 16+也是支持requestAnimationFrame的。
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了。
var lastTime = 0;var prefixes = 'webkit moz ms o'.split(' '); //各浏览器前缀var requestAnimationFrame = window.requestAnimationFrame;var cancelAnimationFrame = window.cancelAnimationFrame;var prefix;//通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式for( var i = 0; i < prefixes.length; i++ ) { if ( requestAnimationFrame && cancelAnimationFrame ) { break; } prefix = prefixes[i]; requestAnimationFrame = requestAnimationFrame || window[ prefix + 'RequestAnimationFrame' ]; cancelAnimationFrame = cancelAnimationFrame || window[ prefix + 'CancelAnimationFrame' ] || window[ prefix + 'CancelRequestAnimationFrame' ];}//如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeoutif ( !requestAnimationFrame || !cancelAnimationFrame ) { requestAnimationFrame = function( callback, element ) { var currTime = new Date().getTime(); //为了使setTimteout的尽可能的接近每秒60帧的效果 var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); var id = window.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall ); lastTime = currTime + timeToCall; return id; }; cancelAnimationFrame = function( id ) { window.clearTimeout( id ); };}//得到兼容各浏览器的APIwindow.requestAnimationFrame = requestAnimationFrame; window.cancelAnimationFrame = cancelAnimationFrame;
这样子我们就能在所有浏览器上使用requestAnimationFrame和cancelAnimationFrame了。
下面举个简单的例子来说明怎么运用requestAnimationFrame进行动画,下面的代码会将id为demo的div以动画的形式向右移动到300px
<div id="demo" style="position:absolute; width:100px; height:100px; background:#ccc; left:0; top:0;"></div><script>var demo = document.getElementById('demo');function rander(){ demo.style.left = parseInt(demo.style.left) + 1 + 'px'; //每一帧向右移动1px}requestAnimationFrame(function(){ rander(); //当超过300px后才停止 if(parseInt(demo.style.left)<=300) requestAnimationFrame(arguments.callee);});</script>
显示器
的定时器值推荐最小使用16.7ms
刷新间隔之前发生了其他绘制请求(setTimeout
),导致所有第三帧丢失,继而导致动画断续显示(堵车的感觉),这就是过度绘制带来的问题。不仅如此,这种计时器频率的降低也会对电池使用寿命造成负面影响,并会降低其他应用的性能。这也是为何setTimeout16.7ms
的原因(16.7 = 1000 / 60, 即每秒60帧)。而我requestAnimationFrame
就是为了这个而出现的。我所做的事情很简单,跟着浏览器的绘制走,如果浏览设备绘制每一帧动画的间隔是16.7ms
,那我就这个间隔绘制;如果浏览设备绘制间隔是10ms
, 我就10ms
绘制。这样就不会存在过度绘制的问题,动画不会掉帧,自然流畅.
统一的向下兼容策略
虽说CSS3实现动画即高效又方便,但是对于PC浏览器,IE8, IE9之流,你想兼容实现某些动画效果,比方说淡入淡出,敢问,你怎么实现?IE10+ CSS3实现,IE9-之流JSsetTimeout
实现,两套完全不同的style. 你改下动画时间是不是要改两处?但是我requestAnimationFrame
跟setTimeout
非常类似,都是单回调,用法也类似。
var handle = setTimeout(renderLoop, PERIOD);var handle = requestAnimationFrame(renderLoop);
我
requestAnimationFrame
调用一次只会重绘一次动画,因此,如果想要实现联系动画,就使用renderLoop
So,如果想要简单的兼容,可以这样子:
window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); };})();但是并不是所有设备的绘制时间间隔是
1000/60 ms
, 以及上面并木有cancel相关方法,所以,就有下面这份更全面的兼容方法:(function() { var lastTime = 0; var vendors = ['webkit', 'moz']; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || // Webkit中此取消方法的名字变了 window[vendors[x] + 'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16.7 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function(id) { clearTimeout(id); }; }}());
然后,我们就可以以使用
setTimeout
的调调使用requestAnimationFrame
方法啦,IE6也能支持CSS3动画不能应用所有属性
使用CSS3动画可以改变高宽,方位,角度,透明度等等。但是,就像六道带土也有弱点一样,CSS3动画也有属性鞭长莫及。比方说scrollTop
值。如果我们希望返回顶部是个平滑滚动效果,就目前而言,CSS3似乎是无能为力的。此时,还是要JS出马,势必,我requestAnimationFrame
大人就可以大放异彩,
转自:http://www.cnblogs.com/2050/p/3871517.html
http://www.zhangxinxu.com/wordpress/2013/09/css3-animation-requestanimationframe-tween-%E5%8A%A8%E7%94%BB%E7%AE%97%E6%B3%95/
- JS-requestAnimationFrame
- js requestanimationframe动画 时间控制
- 优化JS动画之requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- requestAnimationFrame
- JS:指定FPS帧频,requestAnimationFrame播放动画
- JS:指定FPS帧频,requestAnimationFrame播放动画
- 性能更好的js动画实现方式——requestAnimationFrame
- fragment的生命周期详解
- Android 中的 UI Controls
- uva12174 shuffle【方法一】
- loadrunner之 学习三:初次尝试用LR测试接口
- 中文编码问题
- JS-requestAnimationFrame
- EasyUI Combobox的联动处理
- Lucene笔记(2)
- lock cmpxchg指令
- Qt 中文乱码问题
- wpf 异步操作
- 网络服务器搭建的那些事(PV QPS Throughput)
- 我自己对英语学习的心得与体会
- loadrunner之 学习四:web_custom_request()函数