用 requestAnimationFrame 来实现动画

通常我们实现 JavaScript 动画,用的都是 setTimeoutsetInterval,自己设定一个间隔,利用这两个函数来重复地修改 DOM,产生动画效果。这里面有一个问题,就是间隔究竟设为多少才最合适。太大了动画就不平滑,太小了又会过分消耗计算资源,有时还会丢帧。

理论上说,每一次的 DOM 修改都放在显示器刷新前那一刻进行是最合适的,但是我们利用 JavaScript 还做不到这点,无法准确地知道下一次渲染在什么时刻。一般的显示器刷新频率都设置在 60Hz,刷新间隔便是 1/60 s 约为 17ms。 但也并不是给 setInterval 简单地设置个 17ms 就能解决问题了。requestAnimationFrame 的出现就是为了解决这个的。

语法

 window.requestAnimationFrame( callback ) // 也可省略window 

requestAnimationFrame() 方法接受一个回调函数 callback。调用 requestAnimationFrame() 时,浏览器就会在下一次渲染之前执行 callback,然后渲染。所以对 DOM 的修改就可以放在 callback 里面。另外像 setTimeout 一样,我们要在回调函数中再次调用 requestAnimationFrame(),才能将每一帧动画衔接起来。requestAnimationFrame() 的返回值是一个唯一的 id。

setTimeoutsetInterval 的区别就是,requestAnimationFrame 不能自行设定间隔,一旦调用了,浏览器就会自动在下次渲染前的一刻执行代码,所以这个执行的时机一般是在 17ms 以内。 因为对 DOM 的修改和浏览器渲染的步调做到了一致,所以效率更高,动画会很平滑。用 requestAnimationFrame 的另外一个好处就是,当标签页不活动的时候,动作就会暂停,减少了不必要的内存消耗。

浏览器差异

此方法目前还是草案状态,各浏览器的实现不太一致,IE 从版本 10 开始提供支持,其他浏览器的旧版本需要加对应前缀。Chrome 的方法还支持第二个参数:webkitRequestAnimationFrame( callback, element )element 表示属性发生改变的 DOM 元素,这样渲染会局限在该元素中,提高效率。Firefox 的实现 mozRequestAnimationFrame 会在执行回调时,给 callback 传入一个参数 timestamp,是以毫秒表示的时间,表示下一次渲染的精确时刻。

阅读全文 »

flight