[翻译]使用requestAnimationFrame实现炫目的动画
写缓动函数用到requestAnimationFrame函数,之前了解过一些,但总觉得又不是很了解,所以翻译一篇老外的文章,以便学习分享。
requestAnimationFrame是什么?
以前我们做动画需要一个定时器,每间隔多少毫秒就做出一些改变。现在有个好消息:浏览器厂商已经决定提供一个专门做动画的方法,即requestAnimationFrame(),而且基于浏览器的层面也能更好的进行优化。但是呢,这只是一个做动画的基础API,即不基于DOM元素的style变化,也不基于canvas,或者WebGL。所以,具体的动画细节需要我们自己写。
我们为什么要用它?
对于同时进行的n个动画,浏览器能够进行优化,把原本需要N次reflow和repaint优化成1次,这样就实现了高质量的动画。举个例子,现在有基于JS的动画,还有基于CSS的transitions,或者SVG SMIL. Plus,如果浏览器的某个tab正在运行这样一个动画,然后你切到另一个tab,或者干脆最小化,总之就是你看不见它了,这时浏览器就会停止动画。这将意味着更少的CPU,GPU和更少的内存消耗,这样电池的使用寿命就大大延长了。
如何使用它?
// shim layer with setTimeout fallback window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(/* function */ callback, /* DOMElement */ element){ window.setTimeout(callback, 1000 / 60); }; })(); // usage: // instead of setInterval(render, 16) .... (function animloop(){ render(); requestAnimFrame(animloop, element); })();
注意:这里我使用了“requestAnimFrame”,因为规范仍在不断变化中,我并不想任由规范摆布。
requestAnimationFrame API
window.requestAnimationFrame(function(/* time */ time){ // time ~= +new Date // the unix time }, /* optional bounding elem */ elem);
先给出Chrome和Firefox的版本
window.mozRequestAnimationFrame([callback]); // Firefox window.webkitRequestAnimationFrame(callback[, element]); // Chrome
参数:
callback:(FF可选,Chrome必选)
下次repaint调用的函数,函数的第一个参数是当前时间
element:(FF无)
意译一下吧:其实就是画布了,而那个‘画’,是动画。(the element that visually bounds the entire animation)。对canvas和WebGL来说,它就是<canvas>元素,对于DOM节点来说,你可以不管它,如果你想稍微进行一下优化,也可以传个参数进来。
它到底靠不靠谱啊?
现在,Webkit实现(Nightly Safari 和 Chrome Dev Channel 可用)和Mozilla实现(FF4可用)有一些的差异,Mozilla的实现有一个Bug。事实上,FF动画的帧数是这么算的:1000/(16 + N) fps,其中N是callback的执行时间,单位为毫秒。如果你的callback执行时间为1000ms,那么它最高的帧数也就只有1fps。如果你的callback执行时间为1ms,那么帧数差不多就是60fps。这个bug肯定会被修复,也许就是FF4的下一个版本吧。Chrome10没有time参数(added in m11.弱弱的问下,m11是什么?),FF目前没有element参数。
我看了下火狐的那个bug,大概就是说:
FF的mozRequestAnimationFrame()永远不可能达到60fps,即使你的callback执行时间小于1000/60毫秒。举个例子:
function callback(time) { window.mozRequestAnimationFrame(callback); doWork(); }
如果doWork()耗时1000/60毫秒,那么帧数大约是30fps,而同样的动画如果使用setTimeout(callback, 16),帧速则是60fps。似乎callback总是在callback执行完毕后的大约16ms再次开始执行,而不是在callback开始执行后的16ms再次开始执行,如果是后者,且计算又够快的话,就能产生60fps的帧数。
如果你是规范控,传送门在此
来源: