Node.js事件循环对我来说没有意义
Node.js event loop not making sense to me
我是Node.js新手。我一直在努力通过Jim R. Wilson的"Node.js的正确方式",我在书中(以及Node.js本身?)遇到了一个矛盾,我无法通过任何数量的谷歌来调和我的满意。
在书中和我在网上看到的其他资源中反复声明,Node.js逐行运行回调以响应一些事件,直到完成,然后事件循环继续等待或调用下一个回调。因为Node.js是单线程的(并且没有显式地使用集群模块做任何事情,也作为单个进程运行),我的理解是,一次最多只有一个 JavaScript代码块执行。
我理解对了吗?(在我看来)矛盾就在这里。如果是这种情况,Node.js如何具有如此高的并发性?
这是一个直接从书中摘取的例子,说明了我的困惑。它旨在遍历包含数千个XML文件的目录,并将每个文件的相关位提取到JSON文档中。
首先是解析器:
'use strict';
const
fs = require('fs'),
cheerio = require('cheerio');
module.exports = function(filename, callback) {
fs.readFile(filename, function(err, data){
if (err) { return callback(err); }
let
$ = cheerio.load(data.toString()),
collect = function(index, elem) {
return $(elem).text();
};
callback(null, {
_id: $('pgterms'':ebook').attr('rdf:about').replace('ebooks/', ''),
title: $('dcterms'':title').text(),
authors: $('pgterms'':agent pgterms'':name').map(collect),
subjects: $('[rdf'':resource$="/LCSH"] ~ rdf'':value').map(collect)
});
});
};
和遍历目录结构的位:
'use strict';
const
file = require('file'),
rdfParser = require('./lib/rdf-parser.js');
console.log('beginning directory walk');
file.walk(__dirname + '/cache', function(err, dirPath, dirs, files){
files.forEach(function(path){
rdfParser(path, function(err, doc) {
if (err) {
throw err;
} else {
console.log(doc);
}
});
});
});
如果您运行这段代码,您将得到一个错误,因为程序耗尽了所有可用的文件描述符。这似乎表明程序同时打开了数千个文件。
我的问题是……这怎么可能,除非事件模型和/或并发模型的行为不同于它们被解释的方式?我相信有人知道这一点,可以阐明它,但目前,我非常困惑!
我理解对了吗?
是的。
不是javascript执行本身是并发的——IO(和其他繁重的任务)是并发的。当您调用异步函数时,它将启动任务(例如,读取文件)并立即返回"运行脚本的下一行"。然而,该任务将继续在后台(并发地)读取文件,一旦完成,它将把分配给它的回调放到事件循环队列中,该事件循环队列将使用可用数据调用它。如果是这种情况,Node.js是如何高度并发的?
有关"在后台"处理的详细信息,以及node实际上如何管理并行运行所有这些异步任务,请查看问题Nodejs事件循环
这是一个非常简单的描述,省略了很多内容。
files.forEach
不是异步的。因此,代码遍历目录中的文件列表,对每个文件调用fs.readFile
,然后返回到事件循环。
循环然后有一个文件打开事件加载处理,然后将文件读取事件排队。然后循环可以开始通过并调用回调到fs.readFile
与已读取的数据。这些线程一次只能调用一个:正如你所说的,在任何时候只有一个线程在执行javascript。
但是,在调用这些回调函数之前,您已经打开了原始列表中的每个文件,如果文件句柄太多,将导致文件句柄耗尽。
我认为OrangeDog的答案是你具体问题的正确答案。但也许你会发现Philip Roberts的这个简短而精彩的演讲很有帮助,它很好地解释了事件循环的概念和JavaScript的异步处理。注意,该视频与node.js无关,因为这些原则适用于所有JavaScript代码。
- javascript中的闭包对我来说工作方式不同
- Rails JQuery和Ajax对我来说工作不正常
- 如果使用单个实体,使用automapper对我来说很好
- css animate fadeIn'对我来说不起作用
- 对我来说,用javascript设置这个函数最有效的方法是什么
- 文本中的函数示例对我来说没有意义
- 使用 jQuery 编写一个可排序的列表(只是基本功能,jQueryUI 对我来说太重了)
- 通过body onload使用json_encode发送数组对我来说不起作用
- 对我来说,以排序的方式检索这些信息的最佳方式是什么
- javascript有两个奇怪的bug(至少对我来说)
- 在同一个按钮上调用多个函数对我来说不起作用(ajax)
- RegExp(对我来说)并不那么简单
- jQuery's的slideUp功能对我来说无法正常工作
- javascript中的单元测试:如何模拟?-一个(对我来说很难)的例子
- 倒数第二的第n个孩子没有'对我来说不起作用
- 我应该将php json编码转换为Ajax数组,第一次对我来说很难理解
- 否则if语句对我来说似乎是合理的,但会破坏代码
- Node.js事件循环对我来说没有意义
- Javascript -检查页面加载时是否存在cookie对我来说不起作用
- 基本的 for 循环逻辑对我来说没有意义