views:

35

answers:

3

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...

A: 

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.

Andy E
A: 

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.

JBRWilkinson
A: 

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.

Dominic Cooney