1

我想只使用 dispatchEvent 调用在 JavaScript/DOM 中创建一个事件循环机制。

例如:

document.addEventListener("LoopingEvent", loop, true);
var loop = function() {
    doSomeWork();
    updateUI();
    document.dispatchEvent(loopEvent);
};
var loopEvent = document.createEvent('Events');
loopEvent.initEvent("LoopingEvent", true, true);
document.dispatchEvent(loopEvent);

运行时,会引发调用堆栈 OutOfRange 错误。如果我将循环处理程序的调度调用更改为使用 window.setTimeout 延迟,它会循环而不会出错。

只是想知道是否有一种方法可以无限地使用 dispatchEvent 循环而不求助于 setInterval 或 setTimeout?dispatchEvent 循环模式的优点是调用发生在工作完成时而不是在设定的时间间隔内。

在此先感谢您的任何见解...

4

3 回答 3

1

dispatchEvent将事件同步发送到目标,因此当您使用dispatchEvent事件处理程序时,帧会在堆栈上累积并最终溢出。

如果你想简单地“永远循环”,你有几个选择。哪个选择是正确的取决于您希望代码如何与其他事件交互。我注意到您的代码表明它会updateUI()。好吧,您的事件处理程序需要定期返回浏览器的事件循环,以便它可以绘制您更新的 UI。使用setTimeout(loop, 0);是实现此目的的好方法:

function loop() {
  doSomeWork();
  updateUI();
  setTimeout(loop, 0);
}
loop();  // get things started

setTimeoutwill return beforeloop的调用再次被调用;然后浏览器将再次调用loop。在loop对浏览器的调用之间可能会运行其他代码,例如在 UI 中绘制更改,或者调用其他事件处理程序以响应单击和其他事件。

如果您愿意,可以通过将延迟从 0 毫秒增加到更大的值来使循环运行得更慢。如果您的循环正在制作动画,这可能很有用。

如果你想让你的循环停止,那么不要调用setTimeout它也不会再次被调用。

现在这是一种替代技术:

如果您使用的是相对较新的 Firefox、Chrome 或 Safari 版本,您可以使用名为 worker 的新功能来运行您的循环。Worker 有自己的事件循环,因此可以编写如下代码:

// worker code
while (true) {
  doSomeWork();
  // post messages to update the UI
}

Worker 与其他脚本分开运行;要将结果推送到页面本身,您需要使用一个名为postMessage. 这是相关规范,但是您可能还想搜索教程或发布后续问题,因为一开始可能很难完成规范。

于 2010-06-23T13:08:02.227 回答
0

我无法评论 dispatchEvent() 但这种模式有什么问题:

function DoSomeWork()
{
   // do work
   if (moreWorkNeedsDoing)
   {
      setTimeout(DoSomeWork, 0);
   }
}

只要有工作要做,该函数就会“立即”迭代。

于 2010-06-23T12:51:52.040 回答
0

看起来您正在引发一个无限循环,该循环将无限期地继续运行。执行之间的计时器延迟对于让其他函数在线程上排队是必要的。

dispatchEvent 循环模式的优点是调用发生在工作完成时而不是在设定的时间间隔内。

setTimeout延迟为 0ms 可以达到这种效果,尽管循环setTimeoutsetInterval会导致创建另一个无限循环,所以至少需要一些延迟,正如我在上面指出的那样。

于 2010-06-23T12:46:28.923 回答