简体   繁体   English

NodeJS事件循环多个请求

[英]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/ ): 我对以下代码有疑问(来源: 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? 当getWeatherOfRandomCity方法中的superagent.get( wttr.in/${city} )http://wttr.in/sf发出Web请求时,该请求将被置于任务队列而不是主要调用堆栈正确吗?
    1. If there are methods on the main call stack (ie 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? 如果主调用堆栈上有方法(即主调用堆栈不为空),则结束事件附加到superagent.get( wttr.in/${city} ).end(...) (即被推到任务队列)直到主调用堆栈为空是否正确才会被调用? In other words, on every tick of the event loop, it will take one item from the task queue? 换句话说,在事件循环的每个刻度上,它将从任务队列中获取一个项目?
    2. Let's say two requests to localhost:3000/ come in one after another. 假设有两个对localhost:3000/请求localhost:3000/一个接一个地进来。 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. 第一个请求将推送堆栈上的sendWeatherOfRandomCity,堆栈上的getWeatherOfRandomCity,然后将web请求superagent.get( wttr.in/${city} ).end(...)放在后台队列中,然后console.log('Fetching the weather, please be patient') ,然后sendWeatherOfRandomCity将从堆栈弹出,最后sayHi()将被推入堆栈,它将打印“Hi”并弹出堆栈,最后附加到superagent.get( wttr.in/${city} ).end(...)结束事件将从任务队列中调用,因为主调用堆栈将为空。 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? 现在,当第二个请求到来时,它会将所有与第一个请求相同的内容推送到主调用堆栈,但是第一个请求(仍然在任务队列中)的结束处理程序将首先运行,或者将内容推送到主调用第二个Web请求的堆栈会先运行吗?

when you make http request, libuv sees that you are attempting to make a network request. 当您发出http请求时,libuv会发现您正在尝试发出网络请求。 Neither libuv nor node has any code to handle all of these operations that are involved with a network request. libuv和node都没有任何代码来处理网络请求涉及的所有这些操作。 Instead libuv delegates the request making to the underlying operating system. 而是libuv将请求委托给底层操作系统。

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. Libuv用于发出请求,然后它只是等待操作系统发出一个信号,表明某些响应已经回到请求。 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. 因此,由于Libuv将完成的工作委托给操作系统,操作系统本身决定是否制造新的威胁。 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. 每个不同的操作系统都有不同的方法来处理这个:在linux上它是epoll,在mac os中它被称为kqueue,在windows中它被称为GetQueuedCompletionStatusEx。

there are 6 phases in event loop and one of them is i/o poll. 事件循环中有6个阶段,其中一个是i / o轮询。 And every phase has precedence over others. 每个阶段都优先于其他阶段。 number 1 is always timers. 1号总是定时器。 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. 你可以一次做一件事,调用堆栈强制我们只能在调用堆栈的顶部有一个函数,这是我们正在做的事情。在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. 如果调用堆栈为空意味着删除了main()函数,则事件循环将推送定时器函数调用堆栈并执行您的函数。 None of the Async callbacks are EVER going to run before the main function is done. 在主函数完成之前,所有Async回调都不会运行。

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. 因此,当I / O轮询阶段处理传入数据和连接时,使用相同的路径定时器函数如何跟随,将执行处理提取的函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM