如果您一直在使用 requestAnimationFrame
,会很高兴看到渲染与屏幕的刷新率同步,从而生成尽可能高的保真度动画。此外,在用户切换到其他标签页时,您可以减少 CPU 风扇噪音,并节省电池电量。
不过,该 API 的一部分将发生变化。传递到回调函数中的时间戳将从类似于 Date.now()
的典型时间戳更改为以浮点数(自网页打开以来的毫秒数)的高分辨率测量结果。如果您使用此值,则需要根据以下说明更新代码。
需要注意的是,我这里要说的是:
// assuming requestAnimationFrame method has been normalized for all vendor prefixes..
requestAnimationFrame(function(timestamp){
// the value of timestamp is changing
});
如果您使用的是此处提供的通用 requestAnimFrame
shim,则无需使用时间戳值。您现在已经可以开始使用了。:)
原因
原因何在?rAF 可帮助您获得理想的终极 60 fps,而 60 fps 可转换为每帧 16.7 毫秒。但如果用整数毫秒进行测量,则对于我们想要观察和定位的所有内容,我们的精确率为 1/16。
如上所示,蓝色条表示在绘制新帧(60fps)之前必须完成所有工作的最长时间。您可能需要执行超过 16 项操作,但对于整数毫秒,您只能以非常零碎的增量安排和测量。这还不够好。
高分辨率计时器能够提供更精确的数值来解决这个问题:
Date.now() // 1337376068250
performance.now() // 20303.427000007
Chrome 中当前提供的高分辨率计时器为 window.performance.webkitNow()
,该值通常等于传入 rAF 回调的新参数值。一旦符合规范的后续要求,该方法就会舍弃前缀,并可通过 performance.now()
使用。
您还会发现,上述两个值相差不多,数量级。performance.now()
表示从该特定网页开始加载(具体为 performance.navigationStart
)以来的浮点数(以毫秒为单位)。
正在使用
剪裁的关键问题是使用以下设计模式的动画库:
function MyAnimation(duration) {
this.startTime = Date.now();
this.duration = duration;
requestAnimFrame(this.tick.bind(this));
}
MyAnimation.prototype.tick = function(time) {
var now = Date.now();
if (time > now) {
this.dispatchEvent("ended");
return;
}
...
requestAnimFrame(this.tick.bind(this));
}
解决此问题的修改非常简单... 扩充 startTime
和 now
以使用 window.performance.now()
。
this.startTime = window.performance.now ?
(performance.now() + performance.timing.navigationStart) :
Date.now();
这是一个相当简单的实现,它没有使用带前缀的 now()
方法,还假定支持 Date.now()
,但 IE8 中没有此支持。
功能检测
如果您未使用上述模式,只是想确定您获得的回调值类型,则可以使用此方法:
requestAnimationFrame(function(timestamp){
if (timestamp < 1e12){
// .. high resolution timer
} else {
// integer milliseconds since unix epoch
}
// ...
检查 if (timestamp < 1e12)
可以快速测试我们处理的数字有多大。从技术上讲,只有网页连续打开 30 年,才会有误报。但无法测试它是否为浮点数(而不是向下取整为整数)。请求足够多的高分辨率计时器,肯定会在某个时间点获得整数值。
我们计划在 Chrome 21 中推出这项变更,因此,如果您已经在使用以下回调参数,请务必更新您的代码!