[译]Node.js - Event Loop

时间:2021-10-11 22:08:32

介绍

在读这篇博客之前,我强列建议先阅读我的前两篇文章:

  • Getting Started With Node.js

  • Node.js - Modules

    在这篇文章中,我们将学习 Node.js 中的事件循环(event loop)。我们还将了解 Node.js 的代码执行过程。在我第一篇文章中我告诉大家 Node.js 是一个单线程的应用程序。因为 Node.js 运行的是 JavaScript,然而 JavaScript 是不支持多线程的,所以 Node.js 也不支持多线程。但是 Node.js 使用事件和回调(event and callbacks)的概念可以支持并发。这一切归咎都是事件循环(event loop)的功劳。

事件循环(event loop)的工作机制

Getting Started With Node.js 这篇文章中我们已经了解了 Node.js 的架构,其中我们还讨论了 Node.js 的两个主要组件:Google's V8 引擎 和 Libuv。其中事件循环(event loop)是用 C 和 C++ 编写的 Libuv 的一部分。

[译]Node.js - Event Loop

上图是 Node.js 的执行过程,让我们来一步一步理解它。

  1. 每当请求进入 Node.js 的 API 时将会被添加到事件循环(event loop)的队列,因为 Node.js 不能同时处理多个请求。所以,所有的请求进来后将会被添加到事件队列里面。
  2. 现在,你可以在上图中看到一个循环,它总是检查事件或请求是否在事件队列中可用。如果有任何请求可用,那么根据队列的“先进先出”的特性,该请求将会被处理。
  3. Node.js 的事件循环(event loop)是单线程执行的非阻塞 I/O 任务。它将请求发送到 C++ 内部线程池(thread pool),里面可以运行大量的线程任务。这个内部 C++ 线程池(thread pool)是 Libev 组件中开发的事件循环(event loop)的一部分,它可以处理多个请求。事件循环一直检查事件队列中是否存在任务,如果有并且阻塞进程存在,将会有线程池来处理。
  4. 现在,内部线程池(thread pool)可以处理很多请求,就像对数据库请求,对文件的操作等等。
  5. 每当有线程完成任务,将会调用回调函数(callback function),并将响应结果发送回事件循环(event loop)。
  6. 事件循环将响应发送回请求客户端完成一次请求处理。

示例

下面的示例将会展示事件循环(event loop)的工作机制:

var fs = require('fs');
var i = 1;
fs.watch("file.txt", function (event, filename) {
var EventId = "#" + i;
var EventName = " Event: " + event;
var FileName = " FileName: " + filename;
var Time = " Time: " + new Date();
var data = EventId.concat(EventName, FileName, Time, "\n");
console.log(data);
i++;
});
console.log("Now we are watching file.txt\n");

在上面的示例中,第一行加载了 fs 模块用于操作文件系统,并且定义了一个变量 i 来做为计数器。然后使用 fs.watch() 方法来监视 file.txt 文件。这个监视方法的回调函数的参数包含了事件(event)和文件名(filename)。所以,每当文件有变化,这个回调函数将会被调用,并将日志打印到控制台上面。我们将上面的代码保存为 app.js

注:我的 file.txt 文件和 app.js 在同一个目录,我的文件结构如下图如示:

[译]Node.js - Event Loop

现在,我们运行程序,并修改这个 file.txt 文件。当我们保存后,将会看到下面的输出日志:

[译]Node.js - Event Loop

上面的结果显示,当 file.txt 发生任何变化,fs.watch() 的回调函数将会在事件循环(event loop)中被调用,并且事件循环(event loop)将会一直检查文件是否发生了变化。你还可以使用下面的代码将该事件信息记录在一个文件中:

var fs = require('fs');
fs.writeFile('log.txt', '', function (err) {
if (err) throw err;
console.log('File Saved Successfully!');
});
var i = 0;
fs.watch("target.txt", function (event, filename) {
var EventId = "#" + i;
var EventName = " Event: " + event;
var FileName = " FileName: " + filename;
var Time = " Time: " + new Date();
var data = EventId.concat(EventName, FileName, Time,"\n");
fs.appendFile('log.txt', data, function (err) {
if (err) {
console.log(err);
}
});
i++;
});

好了,我希望这篇文章对你有帮助。谢谢!

译:http://www.c-sharpcorner.com/article/node-js-event-loop/