requestAnimationFrame [now] vs performance.now()时间差异 [英] requestAnimationFrame [now] vs performance.now() time discrepancy

查看:73
本文介绍了requestAnimationFrame [now] vs performance.now()时间差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设:rAF now 时间是在触发所有回调集时计算的.因此,在调用该帧的第一个回调之前发生的任何阻塞都不会影响rAF now ,并且准确无误-至少对于该第一个回调而言.

Assumptions: rAF now time is calculated at the time the set of callbacks are all triggered. Therefore any blocking that happens before the first callback of that frame is called doesn't affect the rAF now and it's accurate--at least for that first callback.

在触发rAF设置之前进行的所有performance.now()测量应早于rAF now .

Any performance.now() measurements made before a rAF set is triggered should be earlier than rAF now.

测试:记录之前(发生任何事件之前的基线时间).设置下一个RAF.将rAF now 和实际的 performance.now() before 进行比较,以了解它们之间的差异.

Test: Record before (a baseline time before anything happens). Set the next rAF. Compare rAF now and actual performance.now() to before to see how different they are.

预期结果:

var before = performance.now(), frames = ["with blocking", "with no blocking"], calls = 0;
requestAnimationFrame(function frame(rAFnow) {
  var actual = performance.now();
  console.log("frame " + (calls + 1) + " " + frames[calls] + ":");
  console.log("before frame -> rAF now: " + (rAFnow - before));
  console.log("before frame -> rAF actual: " + (actual - before));

  if (++calls < frames.length) { before = actual; requestAnimationFrame(frame); }
});

// blocking
for (var i = 0, l = 0; i < 10000000; i++) {
    l += i;
}

观察:如果在帧开始之前存在阻塞,则rAF now 时间有时甚至不正确,即使对于第一个帧也是如此.有时第一帧的 now 实际上比记录的之前时间早.

Observations: When there is blocking before the frame starts, the rAF now time is at times incorrect, even for that first frame. Sometimes the first frame's now is actually an earlier time than the recorded before time.

无论是否在帧之前发生阻塞,帧内时间 rAFnow 总是比帧前时间 before 早-甚至当我在之后设置em 时,我进行了第一次测量.即使很少发生,这也可以在没有任何阻止的情况下发生.

Whether there is blocking happening before the frame or not, every so often the in-frame time rAFnow will be earlier than the pre-frame time before--even when I setup the rAF after I take my first measurement. This can also happen without any blocking whatsoever, though this is rarer.

(大多数情况下,我通常会在第一个阻塞帧上出现计时错误.其他情况下很少出现问题,但是如果您尝试运行几次,这种情况偶尔会发生.)

(I get a timing error on the first blocking frame most of the time. Getting an issue on the others is rarer, but does happen occasionally if you try running it a few times.)

通过更广泛的测试,我发现回调之前阻塞的情况很糟糕:100帧中占1%,无阻塞:〜400帧中占0.21645021645021645%,这似乎是由打开窗口或其他可能占用大量CPU的操作引起的由用户.

With more extensive testing, I've found bad times with blocking prior to callback: 1% from 100 frames, no blocking: 0.21645021645021645% from ~400 frames, seemingly caused by opening a window or some other potentially CPU-intensive action by the user.

所以它相当少见,但问题是这根本不应该发生.如果您想用它们来做有用的事情,例如模拟时间,动画等,那么您就需要那些时间才有意义.

So it's fairly rare, but the problem is this shouldn't happen at all. If you want to do useful things with them, simulating time, animation, etc., then you need those times to make sense.

我已经考虑到人们所说的话,但是也许我仍然不了解事情的运作方式.如果这一切都是针对规范的,我会喜欢一些伪代码来在我的脑海中巩固它.

I've taken into account what people have said, but maybe I am still not understanding how things work. If this is all per-spec, I'd love some psuedo-code to solidify it in my mind.

更重要的是,如果有人对我如何解决这些问题有任何建议,那将很棒.我唯一能想到的就是每帧都进行一次自己的 performance.now()测量,并使用它,但是这看起来有点浪费,因为它在每个帧之上都有效地在每个帧上运行两次触发的事件等等.

And more importantly, if anyone has any suggestions for how I could get around these issues, that would be awesome. The only thing I can think of is taking my own performance.now() measurement every frame and using that--but it seems a bit wasteful, having it effectively run twice every frame, on top of any triggered events and so on.

推荐答案

传递给 requestAnimationFrame()回调的时间戳是动画帧开始的时间.在同一帧中调用的多个回调都接收相同的时间戳.因此,如果 performance.now()返回参数值之前,这确实很奇怪,但对于之后那个.

The timestamp passed in to the requestAnimationFrame() callback is the time of the beginning of the animation frame. Multiple callbacks being invoked during the same frame all receive the same timestamp. Thus, it would be really weird if performance.now() returned a time before the parameter value, but not really weird for it to be after that.

以下是相关规范:

当用户代理要使用时间戳为 now 的时间戳运行文档文档的动画帧回调时,它必须运行以下步骤:

When the user agent is to run the animation frame callbacks for a Document document with a timestamp now, it must run the following steps:

  1. 如果文档对象的hidden属性返回的值为true,请中止这些步骤.[PAGE-VISIBILITY]

  1. If the value returned by the document object’s hidden attribute is true, abort these steps. [PAGE-VISIBILITY]

让回调是文档的动画帧回调列表中的条目的列表,按它们添加到列表的顺序.

Let callbacks be a list of the entries in document’s list of animation frame callbacks, in the order in which they were added to the list.

将文档的动画帧回调列表设置为空列表.

Set document’s list of animation frame callbacks to the empty list.

对于回调中的每个条目,依次执行以下操作:调用Web IDL回调函数,将 now 作为唯一参数,如果引发异常,则报告该异常.

For each entry in callbacks, in order: invoke the Web IDL callback function, passing now as the only argument, and if an exception is thrown, report the exception.

因此,您已经为下一个动画帧注册了一个回调(仅说一个).滴答滴答滴答声,BOOM,该动画帧发生的时间:

So you've registered a callback (let's say just one) for the next animation frame. Tick tick tick, BOOM, time for that animation frame to happen:

  1. JavaScript运行时会记录现在的时间和 的标签.
  2. 运行时会临时复制已注册动画帧回调的列表,并清除实际列表(以便在事情花费很长时间以至于下一个动画帧出现时,它们不会被意外调用).
  3. 列表仅包含一件事:您的回调.系统使用 now 作为参数来调用它.
  4. 您的回调开始运行.也许它从未运行过,所以JavaScript优化器可能需要做一些工作.或者,也许操作系统将线程切换到其他系统进程,例如启动磁盘缓冲区刷新或处理一些网络流量,或者其他数十种事情.
  5. 哦,对了,您的回叫.浏览器再次获取CPU,您的回调代码开始运行.
  6. 您的代码调用 performance.now()并将其与作为参数传递的 now 值进行比较.
  1. The JavaScript runtime makes a note of the time and labels that now.
  2. The runtime makes a temporary copy of the list of registered animation frame callbacks, and clears the actual list (so that they're not accidentally invoked if things take so long that the next animation frame comes around).
  3. The list has just one thing in it: your callback. The system invokes that with now as the parameter.
  4. Your callback starts running. Maybe it's never been run before, so the JavaScript optimizer may need to do some work. Or maybe the operating system switches threads to some other system process, like starting up a disk buffer flush or handling some network traffic, or any of dozens of other things.
  5. Oh right, your callback. The browser gets the CPU again and your callback code starts running.
  6. Your code calls performance.now() and compares it to the now value passed in as a parameter.

由于在步骤1和步骤6之间可能经过了短暂但不可忽略的时间,所以 performance.now()的返回值可能表示几微秒,甚至更多一对,已经过去了.那是完全正常的行为.

Because a brief but non-ignorable amount of time may pass between step 1 and step 6, the return value from performance.now() may indicate that a couple of microseconds, or even more than a couple, have elapsed. That is perfectly normal behavior.

这篇关于requestAnimationFrame [now] vs performance.now()时间差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆