Why is 'nextTick' not behaving as expected here? - javascript

The following program will hang in NodeJS, does anybody know why?
ended = false;
events = require('events');
eventEmitter = new events.EventEmitter();
eventEmitter.on('end', function() {
ended = true;
});
setTimeout(function() {
eventEmitter.emit('end');
}, 100);
while (!ended) {
process.nextTick();
}
console.log('ended');

nextTick isn't some kind of yield operation, it's for scheduling a callback to be called the next time the engine is free to do so. It's "hanging" because the while loop's exit condition is never satisfied (and can never be, with that code).

Short answer: because Node.JS is single-threaded.
Long answer: JavaScript is organized into a queue which holds events. These events when fired cannot be stopped until they finish the job. Also no other code can run parallelly, because Node.JS is single threaded. What this means is that this code:
while (!ended) {
process.nextTick();
}
is an infinie loop. The ended variable will never change, because end handler cannot fire until the main event (i.e. the code you've shown us) finishes its job. And it never does.

process.nextTick(); does not call the next cycle of the main loop, the next cycle comes automatically, .nextTick() method is used to call a callback function on the next cycle, info: http://nodejs.org/api/process.html#process_process_nexttick_callback.
while(!ended) is an infinite loop and that's why the application hangs, the ended variable will not change until the current cycle does not end, which is flooded by your while loop.

Related

When does `setTimeout` execute? [duplicate]

I just started to learn Node.js and I need help: At the following code that runs on Node why it is stuck in a loop while it supposedly an asynchronous method? and also not waiting the interval.
class FuelBurner{
constructor(){
console.log("construction set");
this.fuel=0;
this.rate=2.0;
this.polluted=0.0;
}
run(){
while (true){
console.log("i run");
setTimeout( function (){this.polluted+=this.rate},1000);
this.fuel--;
}
}
get_pollution(){
return this.polluted;
}
}
console.log("Hello");
machine = new FuelBurner();
machine.run();
console.log("Why it never gets here?");
Asynchronous operations in JavaScript are put in a queue and only addressed by your code again when the main event loop isn't busy with something else.
You enter the while loop and pass a function to setTimeout.
Then the rest of the loop runs, and the loop starts again.
About a second later, the first timeout finishes and the function is put on the queue to run when the main event loop is free.
The main event loop is still running the while loop, and will do forever since the condition is always met. It never becomes free. It never pulls the function off the queue to run it.

Why callback never gets called/executed inside while loop? [duplicate]

The following example is given in a Node.js book:
var open = false;
setTimeout(function() {
open = true
}, 1000)
while (!open) {
console.log('wait');
}
console.log('open sesame');
Explaining why the while loop blocks execution, the author says:
Node will never execute the timeout callback because the event loop is
stuck on this while loop started on line 7, never giving it a chance
to process the timeout event!
However, the author doesn't explain why this happens in the context of the event loop or what is really going on under the hood.
Can someone elaborate on this? Why does node get stuck? And how would one change the above code, whilst retaining the while control structure so that the event loop is not blocked and the code will behave as one might reasonably expect; wait
will be logged for only 1 second before the setTimeout fires and the process then exits after logging 'open sesame'.
Generic explanations such as the answers to this question about IO and event loops and callbacks do not really help me rationalise this. I'm hoping an answer which directly references the above code will help.
It's fairly simple really. Internally, node.js consists of this type of loop:
Get something from the event queue
Run whatever task is indicated and run it until it returns
When the above task is done, get the next item from the event queue
Run whatever task is indicated and run it until it returns
Rinse, lather, repeat - over and over
If at some point, there is nothing in the event queue, then go to sleep until something is placed in the event queue or until it's time for a timer to fire.
So, if a piece of Javascript is sitting in a while() loop, then that task is not finishing and per the above sequence, nothing new will be picked out of the event queue until that prior task is completely done. So, a very long or forever running while() loop just gums up the works. Because Javascript only runs one task at a time (single threaded for JS execution), if that one task is spinning in a while loop, then nothing else can ever execute.
Here's a simple example that might help explain it:
var done = false;
// set a timer for 1 second from now to set done to true
setTimeout(function() {
done = true;
}, 1000);
// spin wait for the done value to change
while (!done) { /* do nothing */}
console.log("finally, the done value changed!");
Some might logically think that the while loop will spin until the timer fires and then the timer will change the value of done to true and then the while loop will finish and the console.log() at the end will execute. That is NOT what will happen. This will actually be an infinite loop and the console.log() statement will never be executed.
The issue is that once you go into the spin wait in the while() loop, NO other Javascript can execute. So, the timer that wants to change the value of the done variable cannot execute. Thus, the while loop condition can never change and thus it is an infinite loop.
Here's what happens internally inside the JS engine:
done variable initialized to false
setTimeout() schedules a timer event for 1 second from now
The while loop starts spinning
1 second into the while loop spinning, the timer is ready to fire, but it won't be able to actually do anything until the interpreter gets back to the event loop
The while loop keeps spinning because the done variable never changes. Because it continues to spin, the JS engine never finishes this thread of execution and never gets to pull the next item from the event queue or run the pending timer.
node.js is an event driven environment. To solve this problem in a real world application, the done flag would get changed on some future event. So, rather than a spinning while loop, you would register an event handler for some relevant event in the future and do your work there. In the absolute worst case, you could set a recurring timer and "poll" to check the flag ever so often, but in nearly every single case, you can register an event handler for the actual event that will cause the done flag to change and do your work in that. Properly designed code that knows other code wants to know when something has changed may even offer its own event listener and its own notification events that one can register an interest in or even just a simple callback.
This is a great question but I found a fix!
var sleep = require('system-sleep')
var done = false
setTimeout(function() {
done = true
}, 1000)
while (!done) {
sleep(100)
console.log('sleeping')
}
console.log('finally, the done value changed!')
I think it works because system-sleep is not a spin wait.
There is another solution. You can get access to event loop almost every cycle.
let done = false;
setTimeout(() => {
done = true
}, 5);
const eventLoopQueue = () => {
return new Promise(resolve =>
setImmediate(() => {
console.log('event loop');
resolve();
})
);
}
const run = async () => {
while (!done) {
console.log('loop');
await eventLoopQueue();
}
}
run().then(() => console.log('Done'));
Node is a single serial task. There is no parallelism, and its concurrency is IO bound. Think of it like this: Everything is running on a single thread, when you make an IO call that is blocking/synchronous your process halts until the data is returned; however say we have a single thread that instead of waiting on IO(reading disk, grabbing a url, etc) your task continues on to the next task, and after that task is complete it checks that IO. This is basically what node does, its an "event-loop" its polling IO for completion(or progress) on a loop. So when a task does not complete(your loop) the event loop does not progress. To put it simply.
because timer needs to comeback and is waiting loop to finish to add to the queue, so although the timeout is in a separate thread, and may indeed finsihed the timer, but the "task" to set done = true is waiting on that infinite loop to finish
var open = false;
const EventEmitter = require("events");
const eventEmitter = new EventEmitter();
setTimeout(function () {
open = true;
eventEmitter.emit("open_var_changed");
}, 1000);
let wait_interval = setInterval(() => {
console.log("waiting");
}, 100);
eventEmitter.on("open_var_changed", () => {
clearInterval(wait_interval);
console.log("open var changed to ", open);
});
this exemple works and you can do setInterval and check if the open value changed inside it and it will work

Is node.js setTimeout() working?

I'm new to Node.js. Is there something I need to do to get setTimeout() to work?
Here's a code snippet.
async code that sets appMsg.doneLoadTables = true when done
do {
console.log('waiting ... ' + appMsg.doneLoadTables);
setTimeout(function() { console.log('waiting ...'); }, 1000);
} while (!appMsg.doneLoadTables);
Symptoms:
(While the two calls to console.log are similar, only the first prints the value of appMsg.doneLoadTables.) Every result includes that value.
The spacing between calls to console.log is much closer than 1000 msec. (I suspect the spacing is as fast as the computer can process the loop shown here.)
While I would hope the async routines could continue to process during the delays I intended here, I've never seen this loop finish; it's as if the loop takes all processing resources and prevents the async routines from finishing their work and from setting the variable that'll end this loop.
I had this experience with Node 4.2.1; I continue to have this experience after installing Node 5.0.0.
I've seen that similar questions about setTimeout() have been asked here many times before. I hope my use of a IIFE inside setTimeout() makes this question distinct from all of those.
Thanks in advance for any help offered ...
JavaScript is single-threaded. setTimeout is not a form of sleep which pauses code at that line. It works by "scheduling" your callback for later, and execute it when the stack exhausts (the engine doing nothing) and is at least n milliseconds later, where n is the delay you placed in milliseconds.
Now your code doesn't work because it never exits the loop. The code doesn't get the chance to execute other code (the code you hope to run and change appMsg.doneLoadTables's value). All it does keep logging "waiting... [something]".
Essentially you are polling. What you could use instead is setInterval. When appMsg.doneLoadTables is true, you stop the polling by using clearInterval.
I am not 100% sure what is your goal ... however maybe this snippet takes you where you want to go (I opted for setTimeout instead of setInterval):
var appMsg = {doneLoadTables: false};
var stillLoading = function() {
if(false === appMsg.doneLoadTables) {
console.log('waiting ... ' + appMsg.doneLoadTables);
setTimeout(stillLoading, 50);
}
else {
console.log('Loading complete.');
process.exit();
}
}
stillLoading();
setTimeout(function(){
console.log('Setting appMsg.doneLoadTables = true');
appMsg.doneLoadTables = true;
}, 1000);
The script polls status every 50ms and marks "done" exactly after 1 second.
The output looks like this
waiting ... false
waiting ... false
waiting ... false
waiting ... false
...
Setting appMsg.doneLoadTables = true
Loading complete.
(While the two calls to console.log are similar, only the first prints the value of appMsg.doneLoadTables.) Every result includes that value.
That is the correct behavior since you never exit the while loop. You stay in the same event frame that keeps looping forever.
The spacing between calls to console.log is much closer than 1000 msec. (I suspect the spacing is as fast as the computer can process the loop shown here.)
That is the correct behavior again because you callbacks that you passed to setTimeout will never execute unless you exit the do-while loop, which you never do. So you just keep calling first console.log statement then you add a callback to event loop to execute in 1000 ms without ever giving it (the callback that you pass) the chance to execute.
While I would hope the async routines could continue to process during the delays I intended here, I've never seen this loop finish; it's as if the loop takes all processing resources and prevents the async routines from finishing their work and from setting the variable that'll end this loop.
The loop never finish because it doesn't have logic implemented that finishes it. "Async routines" can't continue because that would require exiting the current event frame (that runs infinite loop) and starting the next one that has you callback that you passed to setTimeout.
Hope my explanations will help you to understand how asynchronous JavaScript works.

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.

Categories