JavaScript 中是否可以使用 document.dispatchEvent 循环事件?

发布于 2024-09-06 21:15:45 字数 606 浏览 4 评论 0原文

我想仅使用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 循环模式的优点是,调用在工作完成时发生,而不是在设定的时间间隔内发生。

预先感谢您的任何见解...

I'd like to create an event loop mechanism in JavaScript/DOM using only dispatchEvent calls.

For example:

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);

When run, a call stack OutOfRange error is thrown. If I change the loop handler's dispatch call to use a window.setTimeout delay it loops without error.

Just wondering if there is a way to use dispatchEvent looping infinitely without resorting to setInterval or setTimeout? The advantage in a dispatchEvent looping pattern is that the calls occur when the work is done rather than at set time intervals.

Thanks in advance for any insights...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一袭水袖舞倾城 2024-09-13 21:15:45

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

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

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

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

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

如果您希望循环停止,请不要调用 setTimeout 并且它不会再次被调用。

现在这里有一种替代技术:

如果您使用的是相对较新版本的 Firefox、Chrome 或 Safari,您可以使用称为“workers”的新功能来运行循环。 Workers 有自己的事件循环,因此可以编写这样的代码:

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

Workers 与其他脚本分开运行;要将结果推送到页面本身,您需要使用名为 postMessage 的函数。这是相关规范,但是您可能还想搜索获取教程或发布后续问题,因为一开始按照规范进行工作可能会很困难。

dispatchEvent sends the event synchronously to the target, so when you use dispatchEvent the event handler frames accumulate on the stack and eventually overflow.

If you want to simply "loop forever" you have a few choices. Which choice is correct depends on how you want your code to interact with other events. I notice that your code suggests that it will updateUI(). Well, your event handler needs to return to the browser's event loop periodically so that it can paint your updated UI. Using setTimeout(loop, 0); is a good way to achieve this:

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

The call to setTimeout will return before loop is invoked again; then the browser will invoke loop again. In between calls to loop the browser may run other code, such as painting the changes in the UI, or invoking other event handlers in response to clicks and other events.

If you want you can make your loop run more slowly by increasing the delay from 0 msec to something larger. This might be useful if your loop is doing animation.

If you want your loop to stop, then don't call setTimeout and it won't be called again.

Now here is an alternative technique:

If you are using a relatively recent version of Firefox, Chrome or Safari you can use a new feature called workers to run your loop. Workers have their own event loop, so it is OK to write code like this:

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

Workers run separately from other scripts; to push results into the page itself you need to use a function called postMessage. Here is the relevant spec, however you might want to also search for tutorials or post a follow-up question because working off the spec can be difficult at first.

为人所爱 2024-09-13 21:15:45

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

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

延迟 0 毫秒的 setTimeout 可以达到该效果,尽管循环 setTimeoutsetInterval 会导致创建另一个无限循环,所以至少正如我上面指出的,一些延迟是必要的。

It looks like you're inducing an infinite loop that will continue to run indefinitely. A timer delay between execution is necessary to let other functions queue on the thread.

The advantage in a dispatchEvent looping pattern is that the calls occur when the work is done rather than at set time intervals.

setTimeout with a delay of 0ms would achieve that effect, although a looping setTimeout or setInterval would cause another infinite loop to be created, so at least some delay is necessary, as I pointed out above.

煮酒 2024-09-13 21:15:45

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

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

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

I can't comment about dispatchEvent() but what's wrong with this pattern:

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

The function will iterate 'immediately' as long as there is work to do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文