JavaScript:正在尝试创建 well-behaved 后台作业,但 运行 的时间太少,而系统的其余部分大多处于空闲状态?

JavaScript: trying to create a well-behaved background job, but it gets too little time to run while rest of the system is mostly idle?

在浏览器中,我正在尝试进行这样的 well-behaved 后台作业:

function run() {
  var system = new System();
  setInterval(function() { system.step(); }, 0);
}

系统 object 是什么或步骤函数做什么并不重要 [除非它需要与 UI 交互,在我的情况下,更新 canvas 运行 Conway's Game of Life in the background],activity 执行缓慢,我希望它 运行 更快。但是我已经在 setInterval 中指定了没有等待时间,然而,当我检查 Chrome 中的分析工具时,它告诉我整个事情是 80% 空闲的:

有没有办法让它减少空闲时间并尽最大努力更快地完成我的工作?或者我是否必须创建自己的无限循环,然后以某种方式定期将时间返回给事件循环?

更新: 建议使用 requestIdleCallback,但这样做实际上会使情况变得更糟。 activity 明显变慢了,即使分析数据不是很明显,但空闲时间确实增加了:

UPDATE: 后来有人提出用requestAnimationFrame,我发现又一次和requestIdleCallback方法一样慢和闲,都运行大约是我从标准 setInterval 获得的速度的一半。

PS:我已经更新了所有时间以进行比较,所有三个时间现在都在相同代码 运行ning 的大约 10 秒内。我怀疑递归 re-scheduling 可能是导致速度变慢的原因,但我排除了这一点,因为递归 setTimeout 调用的速度与 setInterval 方法的速度大致相同,而且两者的速度大约是其两倍作为这些新的请求*回调方法。

我在实践中确实找到了可行的解决方案,稍后我会提供自己的答案,但会再等一会儿。

好的,除非有人给出另一个答案,这就是我的最终更新:工作。结果在这里:

  1. setTimeout - 31.056 秒
  2. setInterval - 23.424 秒
  3. requestIdleCallback - 68.149 秒
  4. requestAnimationFrame - 68.177 秒

这为我上面的印象提供了 objective 数据,即带有 request* 的两种新方法的性能会更差。

我也有自己的实用解决方案,可以让我在 55 毫秒(0.055 秒)内完成相同数量的工作,即快 > 500 倍,而且表现仍然相对良好。稍后会对此进行报告。但是想知道其他人能在这里弄清楚什么吗?

我认为这实际上取决于您要实现的目标。

例如,您可以在加载页面时初始化您的 web-worker 并使其 运行 成为后台作业,如果需要,然后将作业的进度或状态传达给主线程你的浏览器。如果您不喜欢使用 post-message 进行线程间通信,请考虑用户 Comlink

  1. Web worker
  2. Comlink

但是,如果您打算做的后台工作不值得 web-worker 做。您可以使用 requestIdleCallback API。我认为它完全符合你在这里提到的内容,因为你已经可以使它递归了。您将不再需要计时器,并且浏览器可以帮助您以不影响页面呈现的方式安排任务(通过将所有内容保持在 60fps)。

类似于 =>

function run() {
 // whatever you want to keep doing
  requestIdleCallback(run)

}

您可以在 MDN 上阅读有关 requestIdleCallback 的更多信息。

好的,我真的不是要阻止其他人获得赏金,但正如您从我添加到我的问题的详细信息中看到的那样,none 这些方法允许高速率执行回调。

原则上 setInterval 是最有效的方法,因为我们已经不需要一直 re-schedule 下一次回调。但这只是一个很小的区别。值得注意的是 requestIdleCallback 和 requestAnimationFrame 当你想被快速回调时是最糟糕的。

因此,我们需要做的不是只执行少量工作然后期望很快被回调,而是需要批量处理更多工作。问题是我们不知道在太多之前我们应该分批处理多少工作。在大多数情况下,这可能可以通过反复试验来解决。

动态地,人们可能会采取计时探测来找出我们被再次回调的速度,并在 call-backs 之间的时间到期时抢先退出工作(某种循环)。