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.
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 fires internally to the JS engine and the timer callback is added to the event queue. This likely occurs on a different thread, internal to the JS engine.
- 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.
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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…