以往JS控制的动画大多使用setInterval
或者setTimeout
每隔一段时间刷新元素的位置,来达到动画的效果,可是这种方式并不能准确地控制动画帧率,尽管主流的浏览器对于这两个函数实现的动画都有必定的优化,可是这依然没法弥补它们性能问题。主要缘由是由于JavaScript的单线程机制使得其可能在有阻塞的状况下没法精确到毫秒触发。css
requestAnimationFrame()
方法正是为了知足高性能动画的需求而提供的API,经过setInterval
方法控制的动画其调用的间隔由程序员设置,而requestAnimationFrame()
无须设置调用间隔, 它自动紧跟浏览器的绘制的帧率(通常浏览器的显示帧率是60fps,差很少每帧间隔16.7ms)html
关于过去的setInterval
控制的动画与requestAnimationFrame()
的效果的对比,这里引用‘艾伦’的帖子中的栗子。原帖地址?动画requestAnimationFramecss3
setInterval动画DEMO
requestAnimationFrame动画DEMO程序员
点击预览以上两个demo能够明显感觉到前者有点卡顿,后者更为流畅。web
另外requestAnimationFrame()
在隐藏或不可见的元素中将不会进行重绘或回流,大大下降了开销。关于该方法的其余细节见MDN文档? window.requestAnimationFrame浏览器
以上都是废话,多写才能体会。这里我尝试用该方法写了个晃动动画(点击黑盒晃动,我的练习并无考虑兼容性):wordpress
动画练习DEMO函数
JS代码:性能
//从网页中获取一个元素 var box = document.getElementById('box') shake(box, 500, 15) //接受三个参数:动画元素,持续时间,晃动距离 function shake(elm, dur, distance) { if (elm) { var dur = dur || 500 var distance = distance || 10 //保存原样式 var original_css = elm.style.cssText elm.addEventListener('click', ani, false) } else { return 'no param' } function ani() { var start = null requestAnimationFrame(act) //requestAnimationFrame每次调用向callback中传入一个时间戳,时间戳为每次调用的时间点 function act(time_stamp) { if(start === null) start = time_stamp var elapsed = time_stamp - start if ((elapsed / dur) < 1) { //乘以4PI,来回往复两次, 使用正弦函数获得比例 elm.style.transform = 'translateX(' + distance * Math.sin((elapsed / dur) * 4 * Math.PI) + 'px' + ')' //调用该方法将返回一个ID值用于结束调用 var time_id = requestAnimationFrame(act) } else { //恢复原样式,中止动画 elm.style.cssText = original_css cancelAnimationFrame(time_id) } } } }
在实际开发中, 固然尽可能使用css动画, 毕竟css动画性能更优。可是对于一些复杂的动画,好比有暂停,继续等复杂交互等动画仍是须要requestAnimationFrame
,在张鑫旭大神的这篇文章中CSS3动画那么强,requestAnimationFrame还有毛线用? 深刻浅出的阐释了该方法, 另外他的demo中也有一个很直观的栗子? 优化
该方法其余参考资料mark下:
性能更好的js动画实现方式——requestAnimationFrame
HTML5探秘:用requestAnimationFrame优化Web动画