使用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
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,则会退到setTimeout if ( !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 ); }; } //得到兼容各浏览器的API window.requestAnimationFrame = requestAnimationFrame; window.cancelAnimationFrame = cancelAnimationFrame;
这样子我们就能在所有浏览器上使用requestAnimationFrame和cancelAnimationFrame了。
下面举个简单的例子来说明怎么运用requestAnimationFrame进行动画,下面的代码会将id为demo的div以动画的形式向右移动到300px
<div></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>
示例二:
一直以来,JavaScript的动画都是通过定时器和间隔来实现的。虽然使用CSS transitions 和 animations使Web开发实现动画更加方便,但多年来以JavaScript为基础来实现动画却很少有所改变。直到Firefox 4的发布,才带来了第一种对JavaScript动画的改善的方法。但要充分认识改善,这有利于帮助我们了解web动画是如何演变改进的。
定时器Timer
用于创建动画的第一个模式是使用链式setTimeout()调用。在Netscape 3′s hayday的很长一段时期,开发者都记得一种在网络上随处可见的固定式最新行情状态栏,通常它类似于这样: