我对以下代码有疑问(来源: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);
我有这些问题:
- 当 getWeatherOfRandomCity 方法中的
superagent.get(
wttr.in/${city})
向http://wttr 发出 Web 请求时。 in/sf
例如,该请求将被放置在任务队列而不是主调用堆栈上,对吗? - 如果主调用堆栈上有方法(即主调用堆栈不为空),结束事件附加到
superagent.get(
wttr.in/${city}).end(...)
(将被推送到任务队列)在主调用堆栈为空之前不会被调用对吗?换句话说,在事件循环的每个滴答声中,它都会从任务队列中取出一个项目? - 假设对
localhost:3000/
的两个请求一个接一个地进来。第一个请求会将 sendWeatherOfRandomCity 压入堆栈,将 getWeatherOfRandomCity 压入堆栈,然后是网络请求superagent.get(
wttr.in/${city}).end(... )
将被放入后台队列,然后是console.log('Fetching the weather, please be patient')
,然后 sendWeatherOfRandomCity 将从堆栈中弹出,最后是sayHi()
将被压入堆栈并打印“Hi”并弹出堆栈,最后,结束事件附加到superagent.get(
wttr.in/${ city).end(...)
将从任务队列中调用,因为主调用堆栈将为空。现在,当第二个请求到来时,它会将与第一个请求相同的所有内容推送到主调用堆栈,但是第一个请求(仍在任务队列中)的结束处理程序会先运行还是将内容推送到主调用第二个网络请求的堆栈将首先运行?
最佳答案
当您发出 http 请求时,libuv 会发现您正在尝试发出网络请求。 libuv 和 node 都没有任何代码来处理所有这些与网络请求有关的操作。相反,libuv 将请求委托(delegate)给底层操作系统。
实际上,内核是我们操作系统的重要组成部分,它负责处理真正的网络请求工作。 Libuv 用于发出请求,然后它只是等待操作系统发出信号,表明某些响应已返回到请求。因此,由于 Libuv 将完成的工作委托(delegate)给操作系统,操作系统本身决定是否制造新威胁。或者一般来说如何处理提出请求的整个过程。每个不同的操作系统都有不同的方法来处理这个问题:在 linux 上它是 epoll,在 mac os 上它被称为 kqueue,在 windows 上它被称为 GetQueuedCompletionStatusEx。
事件循环有 6 个阶段,其中之一是 i/o 轮询。每个阶段都优先于其他阶段。数字 1 始终是计时器。当时间到了(或事件完成)时,定时器的回调将被调用到事件队列,定时器函数也将移动到事件队列。然后事件循环将检查它的调用堆栈是否可用。调用堆栈是函数执行的地方。您一次可以做一件事,调用堆栈强制我们只能在调用堆栈顶部有一个函数,这就是我们正在做的事情。在 JAVASCRIPT RUNTIME 中无法同时执行两件事.
如果调用栈为空意味着 main() 函数被移除,事件循环会将定时器函数压入调用栈,你的函数将被执行。在 main 函数完成之前,任何异步回调都不会运行。
因此,当处理传入数据和连接的 i/o 轮询阶段时间到了,定时器函数遵循的路径相同,您的函数将执行获取句柄。
关于javascript - NodeJS 事件循环多重请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42150622/