1

I am new to NodeJS and I am trying to get my head around how the event loop works in various scenarios.

Take the following code snippet :

console.log("Hello");

setImmediate(() => {
    console.log("Immediate");
    });

console.log("World");

It gives the following output:

Hello
World
Immediate

It only makes sense if you are willing to believe that all async calls happen after all sync calls.

Is that true ? Are all node sync calls suppose to execute before the async calls.

When does the event loop event start ? After parsing the whole file or when the node runtime starts up ? Or when it encounters the first async call ?

I can rationalize the above output only if I accept one of the presumptions, either all async calls happen after sync calls, ie. event loop starts after all sync calls are completed, or setImmediate() here takes more time to complete than console.log()

Which one is correct ?

ng.newbie
  • 2,807
  • 3
  • 23
  • 57
  • 1
    if you think about it as a queue it makes sense – maioman Sep 14 '17 at 14:30
  • This question is a bit too open to be easily answered. It sounds like you need to go read a good resource about the event loop and then come back with a more specific question. While there are good google resources you might start with https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop – Deadron Sep 14 '17 at 14:30
  • What is it that you think `setImmediate` is actually doing? – James Thorpe Sep 14 '17 at 14:31
  • 1
    You should watch this: https://www.youtube.com/watch?v=8aGhZQkoFbQ and check out this SO answer: https://stackoverflow.com/questions/21607692/understanding-the-event-loop – Rob M. Sep 14 '17 at 14:32
  • @JamesThorpe Scheduling a callback to be executed in the `check` phase of the event loop ? – ng.newbie Sep 14 '17 at 14:32
  • Right - in the above scenario it is effectively an async call that completes immediately, but that still means it's at the back of the queue – James Thorpe Sep 14 '17 at 14:35
  • @RobM.I saw that question but it does not answer why it can't be Hello Immediate World as output – ng.newbie Sep 14 '17 at 14:35
  • @JamesThorpe Exactly, while it is at back of the queue, console.log("World") has not been called yet, so can't the runtime just pop setImmediate from the queue and execute it ? I am interested in the time between setImmediate and the second console.log. How can you be sure which goes first – ng.newbie Sep 14 '17 at 14:37
  • @RobM. I have already seen that video but it does not explain why you can't add the setImmediate callback before the second call to console,log. See my comment above – ng.newbie Sep 14 '17 at 14:44
  • @JamesThorpe So far no source has pointed out how JS makes the distinction if it has both async and sync code to be run, in what order does it run ? – ng.newbie Sep 14 '17 at 14:46
  • `setImmediate` causes your arrow function to be queued up, then it continues running the rest of the initial block of code, ie `console.log("world")`. Then it looks to see what's on the queue, which is your arrow function. – James Thorpe Sep 14 '17 at 14:48
  • @JamesThorpe Yeah. Imagine the condition after it has completed `setImmediate`, and just before `console.log`, there setImmediate has completed and waiting in the queue, while the call stack is empty. It can either execute that or go to `console.log` . Why does it make a CHOICE to go to the latter. – ng.newbie Sep 14 '17 at 14:51
  • 1
    The callstack isn't empty - it's still running the initial global script, it _can't_ choose to run the arrow function callback, because it hasn't finished running the initial script yet. – James Thorpe Sep 14 '17 at 14:52
  • @JamesThorpe Would you please care to elaborate on what you mean by its still running the "initial global script" ? – ng.newbie Sep 14 '17 at 14:54

1 Answers1

2

The call stack is populated from synchronous calls (console.log) and the event queue is populated with asynchronous calls (setImmediate). The call stack must be emptied completely before the event loop processes the event queue. Here is effectively what your program looks like on the call stack and event queue:

State 1:

stack                        queue
[console.log('Hello')]       [setImmediate(() => ...)]
[console.log('World')]

State 2:

stack                        queue 
[console.log('World')]       [setImmediate(() => ...)]

State 3:

stack                        queue 
                             [setImmediate(() => ...)]

State 4 (event loop dequeues and pushes to call stack):

stack                        queue 
[console.log('Immediate')]

State 5 (done):

stack                        queue 

You can see a more accurate animation of it here: http://latentflip.com/loupe/?code=Y29uc29sZS5sb2coJ0hlbGxvJykKCnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7CiAgICBjb25zb2xlLmxvZygnSW1tZWRpYXRlJykKfSwgMCkKCmNvbnNvbGUubG9nKCdXb3JsZCcp!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D

Javascript is single-threaded, meaning that it only has one call stack. Browsers (and Node) provide asynchronous APIs to take potentially blocking items off of the call stack and move them to the event queue so that the engine can continue processing the call stack (and not freezing the browser/server) and effectively "background" long-running or blocking operations.

Rob M.
  • 35,491
  • 6
  • 51
  • 50
  • Check ur link, See carefully, that there is a brief time after setTimeout and before console.log, the stack will be empty and there will be a function in the queue. And at that point you could put in the setTimeout function into the callstack rather than console.log, why not do that ? That's my entire question – ng.newbie Sep 14 '17 at 14:59
  • You just showed me that you could in theory put in the setImmediate, before executing any other code – ng.newbie Sep 14 '17 at 15:01
  • Yes it _could_, but that's not what it actually does. The event queue is how this single-threaded language avoids blocking – Rob M. Sep 14 '17 at 15:02
  • Would you please elaborate on that a bit more and add it to your answer – ng.newbie Sep 14 '17 at 15:06
  • @ng.newbie Does it make more sense [if you add an explicit function around the code](http://latentflip.com/loupe/?code=ZnVuY3Rpb24geCgpIHsKICAgIGNvbnNvbGUubG9nKCdIZWxsbycpCiAgICAKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7CiAgICAgICAgY29uc29sZS5sb2coJ0ltbWVkaWF0ZScpCiAgICB9LCAwKQogICAgCiAgICBjb25zb2xlLmxvZygnV29ybGQnKQp9Cgp4KCk7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D)? That's what's going on essentially - the outer "global script" has to run to completion before queued events run in the same way as `x()` does here. – James Thorpe Sep 14 '17 at 15:07
  • Makes perfect sense. That should be in the answer. – ng.newbie Sep 14 '17 at 15:08