0

我正在使用 JavaScript 中的requestAnimFrame方法在程序的主循环中更新画布:

window.requestAnimFrame = (function(callback) {
  return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 1000 / 60);
    };
})();


function animate() {
    requestAnimationFrame( animate );
//var runcount = 100;
//for (var i=0;i<=100;i++) {
    draw();
//    if (runcount === i)
//        alert("Completed program loop");
//    }
}

发生的事情是我的程序仅在我的主循环运行 100次迭代后才更新画布然后停止。在我将上面的方法添加到我的主循环之后,我突然在我的程序的每个循环上都得到了画布更新。

在我的程序完成之前画布没有得到更新的事实让我认为画布更新是在另一个没有获得优先权的线程中运行的。(但我们知道JavaScript 是单线程的)。

我的问题是 -我们可以将 requestAnimFrame 视为应用程序循环上的“yield”以允许事件循环处理吗?我还能假设 JavaScript 是单线程的吗?

4

1 回答 1

1

您并没有具体说明您是如何进行 1000 次迭代的,但我假设您的意思是您使用fororwhile循环进行迭代(如果我错了,请纠正我..)。

当您执行 for/while 循环时,脚本将忙于循环,直到该循环(或范围)完成。正如您所知,JS 是单线程的,它在执行此操作时无法处理诸如事件队列之类的事情 - 因此在循环完成之前没有任何内容能够更新(包括 DOM)(一般来说,可能存在特定于浏览器的例如,如果 DOM 更新在单独的线程上运行,则允许 DOM 更新的实现,但这与 JS 是分开的)。

现在您已经实现了 rAF,您正在每帧进行一次迭代。这意味着浏览器有时间异步处理事件队列(与多线程不同),除非您在循环中处理的代码也做了一段时间的忙循环,这将创建与第一个相同的场景。

你也可以使用setTimeout。rAF 的不同setTimeoutsetInterval处在于它是定时器机制的有效低级实现,能够同步到监视器的VBLANK周期(视频卡通过称为 vsync 的选项从属的垂直消隐) - 用简单的词表示显示器的刷新率(通常为 60 Hz)。这使我们能够创建平滑(er)动画,这就是为什么它被称为 request*Animation*Frame 因为这是它的主要用途。

JS 还是单线程的吗?是的,这不会改变(在 JS 中实现多线程的唯一方法是使用 Web Workers)。

rAF 有什么改变吗?不在这个领域 - 它是一个更准确和高性能的替代方案setTimeout,它的同步方式不同,但仅此而已。它将受到与setTimeout在范围繁忙时无法触发相同的限制(因此request名称的 * 部分表示不保证),但当它触发时,它将与监视器刷新率同步。

于 2014-01-09T03:09:21.487 回答