12

首先,我是初学者,试图了解 Node.Js 是什么。我有两个问题。

第一个问题
来自Felix的文章,它说“只能同时触发一个回调。在该回调完成执行之前,所有其他回调都必须排队等待”。

然后,考虑以下代码(从nodejs官网复制)

var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8124, "127.0.0.1");

如果同时收到两个客户端请求,则表示如下工作流程:

  1. 收到第一个 http 请求事件,收到第二个请求事件。
  2. 一旦收到第一个事件,第一个事件的回调函数就会执行。
  3. 同时,第二个事件的回调函数必须等待。

我对吗?如果我是对的,如果在很短的时间内有数千个客户端请求, Node.js如何控制。

第二个问题
“事件循环”一词主要用于 Node.js 主题。我从http://www.wisegeek.com/what-is-an-event-loop.htm将“事件循环”理解为以下内容;

事件循环(或主循环)是程序中的一种结构,用于控制和调度初始事件之后的事件。

初始事件可以是任何东西,包括按下键盘上的按钮或单击程序上的按钮(在 Node.js 中,我认为初始事件将是 http 请求、数据库查询或 I/O 文件访问)。

这称为循环,不是因为事件循环并不断发生,而是因为循环为事件做准备、检查事件、分派事件并重新重复该过程。

我对第二段有冲突,尤其是“从头再来”这句话。我接受上述问题中的上述http.createServer代码绝对是“事件循环”,因为它反复监听 http 请求事件。

但是我不知道如何识别以下代码是事件驱动还是事件循环。除了 db 查询完成后触发的回调函数之外,它不会重复任何内容。

database.query("SELECT * FROM table", function(rows) {
  var result = rows;
});

请让我听听你的意见和答案。

4

2 回答 2

9

回答一,您的逻辑是正确的:第二个事件将等待。并将在其排队回调时间到来时执行。

同样,请记住,在技术世界中没有“同时”这样的东西。一切都有非常具体的地点和时间。

node.js 管理数千个连接的方式是,当有一些数据库调用阻塞逻辑或另一个 IO 操作正在处理(例如流)时,不需要保持线程空闲。它可以“服务”第一个请求,可能会创建更多回调,然后继续处理其他请求。
因为没有办法阻止执行(除了废话 while(true) 和类似的东西),它在将实际资源分布在整个应用程序逻辑中变得非常有效。

线程 - 很昂贵,线程的服务器容量与可用内存直接相关。因此,大多数经典 Web 应用程序都会受到影响,因为 RAM 用于在有数据库查询块或类似情况时简单空闲的线程上。在节点中,情况并非如此。

尽管如此,它仍然允许通过创建多个线程(作为 child_process)cluster,从而扩展了更多可能性。

答案二。没有您可能想到的“循环”之类的东西。幕后不会有任何循环来检查是否有连接或接收到任何数据等等。现在它也由 Async 方法处理。

所以从应用程序的角度来看,没有“主循环”,从开发人员的角度来看,一切都是事件驱动的(不是事件循环)。

如果是http.createServer,则将回调绑定为对请求的响应。所有的套接字操作和 IO 东西都将在幕后发生,以及 HTTP 握手、解析标头、查询、参数等。一旦它在幕后发生并且工作完成,它将保留数据并将回调推送到带有一些数据的事件循环。一旦事件循环将是免费的并且将到来,它将在 node.js 应用程序上下文中执行您的回调,并使用来自幕后的数据。

使用数据库请求 - 同样的故事。它准备好并询问一些东西(甚至可能再次异步),然后一旦数据库响应并且将为应用程序上下文准备数据就会回调。

老实说,使用 node.js 所需要的只是理解概念,而不是事件的实现。最好的方法——实验。

于 2013-07-11T00:06:12.973 回答
1

1)是的,你是对的。

它之所以有效,是因为您对节点所做的一切主要是 I/O 绑定的。

当一个新的请求(事件)进来时,它被放入一个队列中。在初始化时,Node 分配一个 ThreadPool 负责为 I/O 绑定处理生成线程,例如网络/套接字调用、数据库等(这是非阻塞的)。

现在,您的“回调”(或事件处理程序)非常快,因为您所做的大部分工作很可能是 CRUD 和 I/O 操作,而不是 CPU 密集型操作。

因此,这些回调给人的感觉是它们正在被并行处理,但实际上并非如此,因为实际的并行工作是通过 ThreadPool 完成的(使用多线程),而回调本身只是接收结果来自这些线程,以便处理可以继续并将响应发送回客户端。

您可以轻松地验证这一点:如果您的回调是繁重的CPU 任务,那么您可以确定您将无法每秒处理数千个请求,并且与多线程系统相比,它的缩减非常糟糕。

2)你是对的,再次。

不幸的是,由于所有这些抽象,您必须深入了解背景中发生的事情。但是,是的,有一个循环。

特别是,Nodejs 是用libuv实现的。

有趣的阅​​读

但是我不知道如何识别以下代码是事件驱动还是事件循环。除了 db 查询完成后触发的回调函数之外,它不会重复任何内容。

事件驱动是您通常在有事件循环时使用的术语,它表示由诸如点击按钮、数据到达等事件驱动的应用程序。通常您将回调与此类事件相关联。

于 2017-03-18T15:24:02.660 回答