【发布时间】:2017-06-28 06:49:40
【问题描述】:
我对以下代码有疑问(来源: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.in/sf发出 Web 请求时,该请求将被放置在任务队列中,而不是正确的主调用堆栈? - 如果主调用堆栈上有方法(即主调用堆栈不为空),则附加到
superagent.get(wttr.in/${city}).end(...)的结束事件(将被推送到任务队列)在主调用堆栈为空之前不会被调用,对吗?换句话说,在事件循环的每个滴答声中,它都会从任务队列中取出一项? - 假设两个对
localhost:3000/的请求一个接一个地进来。第一个请求将 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}@ 的结束事件987654334@ 将从任务队列中调用,因为主调用堆栈将为空。现在,当第二个请求到来时,它会将与第一个请求相同的所有内容推送到主调用堆栈上,但第一个请求(仍在任务队列中)的结束处理程序将首先运行,或者推送到主调用的内容第二个网络请求的堆栈将首先运行?
【问题讨论】:
-
您的任务队列概念有缺陷。当您调用异步操作时,它们会立即启动——它们不会进入任务队列。结果完成后将在事件队列中排队,并按照它们排队的顺序(它们完成的顺序,从而触发回调)提供服务。仅当解释器未运行任何其他 Javascript(它是单线程的)时,才会从事件队列中提取事件(这将导致调用回调)。
-
另外传入事件不会以您描述的方式推送到堆栈中。有一个单独的事件队列与堆栈没有连接。当 node.js 运行完所有其他 Javascript 后,它会从事件队列(使用空堆栈)中提取下一个事件并调用与之关联的回调。这会触发该回调中的一些 Javascript 运行。该回调可能以前在函数闭包中保存了状态(它们是被垃圾收集的独立对象,而不是在堆栈上)。
-
但是假设异步操作完成并且它的结果和回调被放置在事件队列中但是主调用堆栈中仍然有代码。那么在主调用栈为空之前不会调用事件队列中的回调对吗?
-
正确。 node.js 是单线程的,一次一件事。它运行当前的 JS 片段,直到将控制权返回给系统,此时它从事件队列中提取下一个事件并运行与之关联的回调。每个回调都从一个空堆栈开始。这就是 nodejs 描述“事件驱动”的意思。事件发生,运行与该事件关联的一些 Javascript,完成该 Javascript,查看事件队列中是否有另一个事件并运行它等等。
-
只有一个 Javascript 堆栈,每次调用事件队列的回调时,堆栈都是空的。所以我不知道你的问题是什么意思,因为这意味着可能有不止一个堆栈。只有一个。
标签: javascript node.js events event-loop