我在JavaScript中使用requestAnimFrame
method在我程序的主循环中更新画布:
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");
// }
}
发生的事情是my program that only updated the canvas after my main loop had run for 100次迭代然后停止了。在我的程序的每个循环上添加method above into my main loop, suddenly I get canvas updates之后。
在我的程序完成之前画布没有得到更新的事实让我认为画布更新是在一个没有优先级的不同线程中运行的。 (但我们知道JavaScript is single-threaded)。
我的问题是 - 我们可以将requestAnimFrame视为应用程序循环上的'yield'以允许事件循环处理吗?我仍然可以假设JavaScript是单线程的吗?
答案 0 :(得分:0)
你没有具体说明你如何进行1000次迭代,但我认为你的意思是你使用for
或while
循环进行迭代(如果我错了,请纠正我... )。
执行for / while循环时,脚本将忙于循环,直到该循环(或范围)完成。正如您所知道的JS是单线程的,它在执行此操作时无法处理诸如事件队列之类的事情 - 因此在循环结束之前没有任何东西能够更新(包括DOM)(一般来说,可能存在特定于浏览器的情况)例如,如果在单独的线程上运行DOM更新,则允许DOM更新的实现,但这与JS是分开的。)
现在你已经实现了rAF,你每个帧进行一次迭代。这意味着浏览器有时间异步处理事件队列 (与多线程不同),除非您在循环中处理的代码也会暂时忙于循环,这将创建相同的场景作为第一个。
您也可以使用setTimeout
。 rAF与例如setTimeout
或setInterval
的不同之处在于它是一种有效的低级别定时器机制实现,能够与监视器的VBLANK周期同步(视频垂直消隐)通过一个名为vsync的选项从卡到奴隶) - 用普通词表示监视器的刷新率(通常为60赫兹)。这允许我们创建平滑(呃)动画,这就是为什么它被称为请求*动画*框架,因为这是它主要用于它。
JS还是单线程吗?是的,这不会改变(在JS中实现多线程的唯一方法是使用Web Workers)。
rAF会改变什么吗?不是在这个区域 - 它是setTimeout
的更准确和高效的替代方案,它的同步方式不同,但就是全部。它将受到与setTimeout
无法在范围繁忙时触发的限制相同的限制(因此名称的request
*部分意味着无法保证)但是当它触发时它将在与显示器刷新率同步。