Is looping events in JavaScript using document.dispatchEvent possible? - javascript

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

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.

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.

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.

Related

wait in while loop for external variable change or event?

I've a question/problem with an whileloop
I need to wait until something changes outside the while loop.
Let's say i have this while loop:
window.changeMe = true;
while(window.changeMe){
}
now i have these two options:
Change the changeMe variable via the Console/JavaScript Execution
Change the changeMe variable via an WebSocket Event
but neither is working, if i change the Variable directly, it is not changed.
If i trigger an WebSocket Event its not getting called.
Maybe its BLOCKED.. so is there any other way to change the variable?
I known i can use await and its already working that way, but the problem is that these functions with while are called via an Addon
and using many await's looks kinda ugly for the addon creator :(
an system with setTimeout & Callbacks are also working but also looks kinda ugly..
Yes, you are correct. Having a infinite while loop will prevent executing any other code from javascript event loop which occupies the main thread.
In order to imitate the same behavior you can implement your own while loop that is friendly to asynchronous events and external code execution. You have to use:
tail recursion in order to minimize the memory footprint,
setTimeout as a mechanism to allow other parts of your code to run asynchronously.
EXAMPLE:
window.changeMe = true;
let stop = setTimeout(() => { console.log("External change stop"); window.changeMe = false; }, 4000)
var whileLoop = () => {
console.log("Inside: ", window.changeMe)
return window.changeMe
? setTimeout(() => { whileLoop(); }, 0)
: false
}
whileLoop()
console.log("Outside: ", window.changeMe)
Here is a fiddle:
https://jsfiddle.net/qwmosfrd/
Here is a setInterval fiddle:
https://jsfiddle.net/2s6pa1jo/
Promise return value example fiddle:
https://jsfiddle.net/0qum6gnf/
JavaScript is single-threaded. If you have while (true) {}, then nothing else outside the while loop can change the state of your program. You need to change your approach. You probably want to set up event listeners instead or put this inside an async function so you can use await to release execution, or some other asynchronous API. But plain vanilla while () {} is synchronous and cannot be affected by other things while it is running.
You can't use a while loop in that way in nodejs.
Nodejs runs your Javascript in a single thread and the overall architecture of the environment is event driven. What your while loop is doing is a spin loop so while that loop is running, no other events can ever run. You have to return control back to the event loop before any other events can run. That means that timers, network events, etc... cannot run while your spin loop is running. So, in nodejs, this is never the right way to write code. It will not work.
The one exception could be if there was an await inside the loop which would pause the loop and allow other events to run.
So, while this is running:
while(window.changeMe){
}
No other events can run and thus nothing else gets a chance to change the changeMe property. Thus, this is just an infinite loop that can never complete and nothing else gets a chance to run.
Instead, you want to change your architecture to be event driven so that whatever changes the changeMe property emits some sort of event that other code can listen to so it will get notified when a change has occurred. This can be done by having the specific code that changes the property also notify listeners or it can be done by making the property be a setter method so that method can see that the property is being changed and can fire an event to notify any interested listeners that the value has changed.

Understanding async using setTimeout

I have a UI where I need animations to run smoothly. Every so often, I need to do a semi-large data calculation that makes the animation skip until it is this calculation is completed.
I am trying to get around this by making the data calculation async with setTimeout. Something like setTimeout(calcData(), 0);
The whole code is something like this (simplified):
while (animating) {
performAnimation();
if (needCalc) {
setTimeout(calcData(), 0);
}
}
But I still get a skip in the animation. It runs smoothly when I do not need to do any data calculations. How can I do this effectively? Thanks!
You are seeing the skip because only one javascript thread is run at once. When something is done asynchronously the javascript engine puts it a queue to be ran later, then finds something else to execute. When something in the queue needs to be done the engine will pull it out and execute it, blocking all other operations until it completes.The engine then pulls something else out of its queue to execute.
So if you want to allow your render to run smoothly you must break up your calculation into multiple async calls, allowing the engine to schedule the render operation in between calculations. This is easy to accomplish if you are just iterating over a array, so you can do something like:
var now=Date.now;
if(window.performance&&performance.now){//use performace.now if we can
now=performance.now;
}
function calculate(){
var batchSize=10;//If you have a exceptionally long operation you may want to make this lower.
var i=0;
var next=function(){
var start=now();
while(now()-start<14){//14ms / frame
var end=Math.min(i+batchSize,data.length);
for(;i<end;i++){//do batches to reduce time overhead
do_calc(data[i]);
}
}
if(i<data.length) setTimeout(next,1)//defer to next tick
};
next();
}
calculate();
function render(){
do_render_stuff();
if(animating) {
requestAnimationFrame(render);//use requestAnimationFrame rather then setTimeout for rendering
}
}
render();
Better yet, if you can, you should use WebWorkers which work in a different thread, completely separate from the main js engine. However you are stuck with this if you need to do something you cant do in a WebWorker, such as manipulating the DOM tree.
Firstly, let's talk what's going on in your code:
while (animating) {
performAnimation();
if (needCalc) {
// it should be setTimeout(calcData, 0);
setTimeout(calcData(), 0);
}
}
In line setTimeout(calcData(), 0); really you don't defer calling of calcData function, you call it, because you use () operator after function name.
Secondly, lets think, what's going on when you really make defer calling for calcData in the code above: commonly JavaScript is running in one thread, so, if you have code like this:
setTimeout(doSomething, 0);
while (true) {};
doSomething will never be called, because interpreter of javascript executes while loop forever and it hasn't "free time" to execute other things (even UI) . setTimeout - just say to schedule execution of doSomething when interpreter will be free and it's time to execute this function.
So, when browser executes javascript function, all other stuff become freezing.
Solution:
If you have big data that you need to process, maybe it would be better to make calculations on backend and after send results to frontend.
Usually when you need to make some calculation and render results it's better to use requestAnimationFrame than while loop. Browser will execute function passed in requestAnimationFrame as soon as possible, but also you give browser a time to handle other events. You can see smooth redrawing using requestAnimationFrame for game (step-by-step tutorial here).
If you really want to process huge amount of data at frontend part and you want to make ui works smooth, you can try to use WebWorkers. WebWorkers look like threads in JavaScript, you need to communicate between main UI "thread" and WebWorker by passing messages from one to another and back and calculations on WebWorker don't affect UI thread.
Mostly, your problem boils down to your incorrect usage of setTimeout()
setTimeout(calcData(), 0);
The first argument to setTimeout is a REFERENCE to the function that you wish to call. In your code, you are not referencing the calcData function, you are invoking it because you've included () after the function name.
Second, the fact that you've put 0 for the delay does not mean you will have a 0 second delay before the function runs. JavaScript runs in a single threaded context. The setTimeout function is placed in a queue and executed when the JavaScript engine is available, but no sooner than a minimum of 10ms or the amount you specify (whichever is less).
Realistically, your line should be:
setTimeout(calcData(),10);

How to break while loop outside it

this is not a common condition, but what's the misuse of it?
var t = true;
setTimeout(function(){
t=false;
},1000);
while(t){
//loop...
//if t==false, break loop.
}
another condition, it causes endless loop too:
button.onlcick = function(){
t = false;
}
JavaScript is single-threaded; setTimeout callback won't be called when you're blocking the main event loop with that while (while (t) { ... }).
If you're running your code in browser, you can't really do anything about it but writing your code in other way;
Instead of blocking the main event loop, you can use Promises Pattern.
If you're running your code in something like node you can use native modules, making you able to create threads (like threads_a_gogo.)
Because the while loop never exits, your other code is never run when something is done synchronously. My best offer for you would be not to use a while loop and instead have a recurring event such as setTimeout and make the timeout run itself when complete.
This way you're not creating a closed environment.
It won't work because javascript is not multithreaded - until your current thread of execution ends (and it won't as long as you're running your while loop), no other code is executed (no timeout call) and the UI is frozen (button clicks will not respond).
There might be a way to do something like that with the new Web Workers feature in html5, but as of now i'm not able to tell with certainty.
you can use labels with break condition like
outer:while()
{
//code
if()
break outer;
}

Why are some JavaScript developers using setTimeout for one millisecond? [duplicate]

This question already has answers here:
Why is setTimeout(fn, 0) sometimes useful?
(19 answers)
Closed 9 years ago.
I have problem when using jQuery plugin tablesorter and I can't call trigger twice.
For example this won't work:
this._$table.trigger('update');
this._$table.trigger('sorton', [[[1,1]]]);
But this works:
this._$table.trigger('update');
setTimeout($.proxy(function() {
this._$table.trigger('sorton', [[[1,1]]]);
}, this), 1);
And then I see that problem was in trigger 'update', it call method with body:
function () {
var me = this;
setTimeout(function () {
// rebuild parsers.
me.config.parsers = buildParserCache(
me, $headers);
// rebuild the cache map
cache = buildCache(me);
}, 1);
}
Why did the tablesorter developer use setTimeout with one millisecond?
Short asnwer: Function execution queueing
This is the short answer to your question. setTimeout with either 0 or 1 millisecond is used for function execution queueing. Read on to find out why and how.
Javascript has single threaded execution
Javascript engine is a single threaded process. So whenever developers wanted to defer some function execution to get executed right after the current one that's just being executed, a setTimeout is being used to actually queue the next function... It doesn't have anything to do directly with events although functions may be event handlers. The only event in this equation is the timeout event that setTimeout creates.
This is an example of two functions where the first function during its execution queues a second function to be executed right after it.
function first()
{
// does whatever it needs to
// something else needs to be executed right afterwards
setTimeout(second, 1);
// do some final processing and exit
return;
}
function second()
{
// whatever needs to be done
}
So to javascript engine thread the execution queue looks like this:
first()
second()
Mind that this has nothing to do with function call stack.
Why 1ms?
1ms is a very short amount of time, which (almost) assures that your second function will get executed right after your first function returns. You may see sometimes even 0ms which actually executes it right after first function returns.
If one would on the other hand use longer time i.e. 100ms this could result in a different function getting executed in the meantime and that could have an undesired effect on the whole UI process.
Why function queueing in the first place?
Browsers nowadays prevent client side functionality to hang current browser session by observing long running functions. If a particular function runs long enough, browser Javascript execution engine will pause it and ask the user whether they want to terminate it (kill it) or wait for it to complete.
This is usually undesired effect when you actually do have a long running function. For instance imagine you have a function that has to loop through a large number of items processing each one during the process. You definitely don't want the user to terminate the process because the loop needs to execute.
What's the solution in this case? In such case instead of having a single function with loop and executing it, you'd rather have the loop (queueing) function that would then queue function calls for processing each item. This is just an outer skeleton of such functionality.
function queueItems(items) {
for(var i = 0; i < items.length, i++)
{
setTimeout((function(item) {
return function() {
processItem(item);
};
})(items[i]), 0);
}
}
function processItem(item) {
// process individual item
}
This way you'd prevent your functions to run too long and after each executed function control would get back to Javascript engine resetting its function-hang timer. But be aware that while your functions are being executed your UI will likely be unresponsive or at most unpredictable. It may be better to queue your function with some time space in between so UI stays responsive if that's desired.
It's an old hack. If an event needs to be triggered after another event you can use setTimeout with 1ms to make sure the event is triggered after the other event.
I think that since trigger('update') internally has a setTimeout, only by setting another setTimeout you can achieve the desired order of statement execution. If you don't call 'sorton' through setTimeout it will be executed before 'update'.
On the other hand I guess 'update' uses setTimeout for preventing 'update' from being a blocking function when it may take a long time to be executed.

What are the proper use cases for process.nextTick in Node.js?

I have seen process.nextTick used in a few places and can't quite tell what it's being used for.
https://github.com/andrewvc/node-paperboy/blob/master/lib/paperboy.js#L24
https://github.com/substack/node-browserify/blob/master/index.js#L95
What are the main/proper use cases of process.nextTick in Node.js? The docs basically say it's a more optimized way of doing setTimeout, but that doesn't help much.
I used to do a lot of ActionScript, so the idea of "waiting until the next frame" to execute code makes sense on some level - if you're running an animation you can have it update every frame rather than every millisecond for example. It also makes sense when you want to coordinate setting a bunch of variables - you change the variables in frame 1, and apply the changes in frame 2. Flex implemented something like this in their component lifecycle.
My question is, what should I be using this for in server-side JavaScript? I don't see any places right off the bat where you'd need this kind of fine-tuned performance/flow control. Just looking for a point in the right direction.
process.nextTick puts a callback into a queue. Every callback in this queue will get executed at the very beginning of the next tick of the event loop. It's basically used as a way to clear your call stack. When the documentation says it's like setTimeout, it means to say it's like using setTimeout(function() { ... }, 1) in the browser. It has the same use cases.
One example use case would be, you create a constructor for some object that needs events bound to it. However, you can't start emitting events right away, because the code instantiating it hasn't had time to bind to events yet. Your constructor call is above them in the call stack, and if you continue to do synchronous things, it will stay that way. In this case, you could use a process.nextTick before proceeding to whatever you were about to do. It guarantees that the person using your constructor will have time enough to bind events.
Example:
var MyConstructor = function() {
...
process.nextTick(function() {
self._continue();
});
};
MyConstructor.prototype.__proto__ = EventEmitter.prototype;
MyConstructor.prototype._continue = function() {
// without the process.nextTick
// these events would be emitted immediately
// with no listeners. they would be lost.
this.emit('data', 'hello');
this.emit('data', 'world');
this.emit('end');
};
Example Middleware using this constructor
function(req, res, next) {
var c = new MyConstructor(...);
c.on('data', function(data) {
console.log(data);
});
c.on('end', next);
}
It simply runs your function at the end of the current operation before the next I/O callbacks. Per documentation you can use it run your code after the callers synchronous code has executed, potentially if you can use this to give your API/library user an opportunity to register event handlers which need to be emitted ASAP. Another use case is to ensure that you always call the callbacks with asynchronously to have consistent behaviours in different cases.
In the past process.nextTick would be have been used provide an opportunities for I/O events to be executed however this is not the behaviour anymore and setImmediate was instead created for that behaviour. I explained a use case in the answer of this question.
"Every callback in this queue will get executed at the very beginning of the next tick of the event loop" is not correct. Actually, nextTick() runs right after completing the current phase and before starting the next phase. Minute details are important!
A function passed to process.nextTick() is going to be executed on the current iteration of the event loop, after the current operation ends. This means it will always execute before setTimeout and setImmediate.
Understanding setImmediate()

Categories