NodeJS Event Loop Multiple Request

I have a question on the following code below (Source: https://blog.risingstack.com/node-js-at-scale-understanding-node-js-event-loop/):

'use strict'  
const express = require('express')  
const superagent = require('superagent')  
const app = express()

app.get('/', sendWeatherOfRandomCity)

function sendWeatherOfRandomCity (request, response) {  
  getWeatherOfRandomCity(request, response)
  sayHi()
}

const CITIES = [  
  'london',
  'newyork',
  'paris',
  'budapest',
  'warsaw',
  'rome',
  'madrid',
  'moscow',
  'beijing',
  'capetown',
]

function getWeatherOfRandomCity (request, response) {  
  const city = CITIES[Math.floor(Math.random() * CITIES.length)]
  superagent.get(`wttr.in/${city}`)
    .end((err, res) => {
      if (err) {
        console.log('O snap')
        return response.status(500).send('There was an error getting the weather, try looking out the window')
      }
      const responseText = res.text
      response.send(responseText)
      console.log('Got the weather')
    })

  console.log('Fetching the weather, please be patient)
}

function sayHi () {  
  console.log('Hi')
}

app.listen(3000);

I have these questions:

  1. When the superagent.get(wttr.in/${city}) in the getWeatherOfRandomCity method makes a web request to http://wttr.in/sf for example, that request will be placed on the task queue and not the main call stack correct?
  2. If there are methods on the main call stack (i.e. the main call stack isn't empty), the end event attached to the superagent.get(wttr.in/${city}).end(...) (that will be pushed to the task queue) will not get called until the main call stack is empty correct? In other words, on every tick of the event loop, it will take one item from the task queue?
  3. Let's say two requests to localhost:3000/ come in one after another. The first request will push the sendWeatherOfRandomCity on the stack, the getWeatherOfRandomCity on the stack, then the web request superagent.get(wttr.in/${city}).end(...) will be placed on the background queue, then console.log('Fetching the weather, please be patient'), then the sendWeatherOfRandomCity will pop off the stack, and finally sayHi() will be pushed on the stack and it will print "Hi" and pop off the stack and finally, the end event attached to superagent.get(wttr.in/${city}).end(...) will be called from the task queue since the main call stack will be empty. Now when the second request comes, it will push all of those same things as the first request onto the main call stack but will the end handler from the first request (still in the task queue) run first or the stuff pushed onto the main call stack by the second web request will run first?

Solution 1:

when you make http request, libuv sees that you are attempting to make a network request. Neither libuv nor node has any code to handle all of these operations that are involved with a network request. Instead libuv delegates the request making to the underlying operating system.

It's actually the kernel which is the essential part of our operating system that does the real network request work. Libuv is used to issue the request and then it just waits on the operating system to emit a signal that some response has come back to the request. So because Libuv is delegating the work done to the operating system the operating system itself decides whether to make a new threat or not. Or just generally how to handle the entire process of making the request. Each different os has a different method to handle this: On linux it is epoll, in mac os it is called kqueue, and in windows it is called GetQueuedCompletionStatusEx.

there are 6 phases in event loop and one of them is i/o poll. And every phase has precedence over others. number 1 is always timers. When time is up,(or event is done) timer's callback will be called to event queue and timer function are gonna move to event queue as well. Then event loop will check if it call stack is available. Call stack is where functions go to execute. You can do one thing at a time and the call stack enforces that we can only have one function on the top of the call stack that is the thing we're doing.There's no way to execute two things at the same time in JAVASCRIPT RUNTIME.

if the call stack is empty means main() function is removed, event loop will push the timer function to call stack and your function will be executed. None of the Async callbacks are EVER going to run before the main function is done.

So when it is time for i/o poll phase which handles incoming data and connections, with the same path how timer function followed, your function with handles the fetching will be executed.