文章目录
  1. 1. 历史原因
  2. 2. 各浏览器实现
    1. 2.1. mozRequestAnimationFrame
    2. 2.2. webkitRequestAnimationFrame 与 msRequestAnimationFrame
  3. 3. 使用
  4. 4. 引用文献

requestAnimationFrame是浏览器用于定时循环操作的一个接口,类似于setTimeout。那既然类似于setTimeout,为什么还会出现这样的一个新兴的API呢?

历史原因

很长时间以来,计时器和循环间隔一直是js动画的核心技术。早期实现动画的基本技术是使用setInterval:

1
2
3
4
5
6
7
8
(function(){
function animation(){
doAnimation1();
doAnimation2();
...
}
setInterval(animation,100);
})();

编写这种动画循环的关键是要知道延迟多长时间合适。一方面:循环间隔必须足够短,这样才能让不同的动画效果显得更平滑流畅;另一方面:循环间隔还要足够长,这样才能确保浏览器有能力渲染产生的变化。

大多数电脑的显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次,大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑的动画的最佳循环时间间隔是1000ms/60,约等于17ms。以这个循环间隔重绘的动画是最平滑的,因为这个速度最接近浏览器的最高限速。setTimeout()与setInterval()中的时间参数只是指定了把动画添加在浏览器UI线程队列中以等待执行的时间,并不一定立即执行,所以并不精确。

知道什么时候绘制下一帧是保证动画平滑的关键,但是目前并没有办法确保浏览器按时绘制下一帧。并且浏览器的计时器的精度也各不相同。 chrome的计时器精度是4ms, Firefox 和Safari大约是19ms…并且浏览器开始限制后台标签页或不活动标签页的计时器。

各浏览器实现

mozRequestAnimationFrame

css变换的动画的优势在于浏览器知道动画什么时候开始,因此会计算出正确的时间间隔,在恰当的时间刷新UI(Robert O’Callahan)。所以根据这个原理,可以告诉浏览器什么时候开始动画,这样浏览器可以在运行某些代码后进行适当的优化。
mozRequestAnimationFrame() 接收一个函数,这个函数负责改变下一次重绘时的DOM。并且这个函数也会接收一个参数,这个参数是个时间码(从1970年1月1日起至今的毫秒数),表示下一次重绘的实际发生时间。这样就会解决浏览器不知道javascript动画什么时候开始、不知道最佳循环间隔时间的问题。两者的使用:

1
2
3
4
5
6
7
8
function updateProgress(){
var div = document.getElementById("status");
div.style.width = (parseInt(div.style.width,10)+5)+'%';
if(div.style.left != "100%"){
mozRequestAnimationFrame(updateProgress);
}
}
mozRequestAnimationFrame(updateProgress);

1
2
3
4
5
6
7
8
9
var startTime = mozAnimationStartTime;
function draw(timestamp){
// diff 是两次重绘的时间间隔
var diff = timestamp -startTime;
start = timestamp;
mozRequestAnimationFrame(draw);
}
mozRequestAnimationFrame(draw);

webkitRequestAnimationFrame 与 msRequestAnimationFrame

这两个API 分别是chrome 和IE10+ 的和Firefox 的mozRequestAnimationFrame 的类似的实现。这两个函数不会给回调函数传递时间码。因此无法知道下一次重绘将会发生在什么时间。对于chrome的webkitRequestAnimationFrame 的第二个可选的参数是即将发生变化的DOM元素,知道了重绘将发生在页面中哪个特定的区域内,就可以将重绘限定在该区域中。

使用

在不需要知道精确地时间差是,可以用下面的方式创建动画循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(function(){
function draw(timestamp){
//计算两次重绘的时间间隔
var drawStart = (timestamp || Date.now()),
diff = drawStart- startTime;
startTime = drawStart;
requestAnimationFrame(draw);
}
var startTime = window.mozAnimationStartTime || Date.now();
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();

引用文献

  1. 《javascript高级程序设计》
文章目录
  1. 1. 历史原因
  2. 2. 各浏览器实现
    1. 2.1. mozRequestAnimationFrame
    2. 2.2. webkitRequestAnimationFrame 与 msRequestAnimationFrame
  3. 3. 使用
  4. 4. 引用文献