我是Node.js的新手。我一直在努力通过" 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);
}
});
});
});
如果运行此代码,则会因程序耗尽所有可用文件描述符而导致错误。这似乎表明该程序同时打开了数千个文件。
我的问题是......除非事件模型和/或并发模型的行为与解释它们的方式不同,否则这怎么可能呢?
我确定那里有人知道这一点,并且可以解释它,但是目前,让我很困惑!
答案 0 :(得分:4)
我理解正确吗?
是
如果是这种情况,Node.js如何高度并发?
不是javascript执行本身是并发的 - IO(和其他繁重的任务)是。当您调用异步函数时,它将启动任务(例如,读取文件)并立即返回“运行脚本的下一行”。然而,任务将在后台(同时)继续读取文件,一旦完成,它将把已分配给它的回调放到事件循环队列中,该队列将使用当时可用的数据调用它。
有关此“在后台”处理的详细信息,以及节点如何实际设法并行运行所有这些异步任务,请查看问题Nodejs Event Loop。
答案 1 :(得分:2)
这是一个非常简单的描述,并且跳过很多东西。
files.forEach
并非荒谬。因此,代码遍历目录中的文件列表,在每个文件上调用fs.readFile
,然后返回到事件循环。
然后循环有一大堆要处理的文件打开事件,然后排队文件读取事件。然后循环可以开始通过并使用已读取的数据调用回调到fs.readFile
。这些只能一次调用一个:正如你所说,任何时候只有一个线程执行javascript。
但是,在调用任何这些回调之前,您已经打开了该原始列表中的每个文件,如果有太多文件,则会导致文件句柄耗尽。
答案 2 :(得分:0)
我认为OrangeDog的答案是对您具体问题的正确答案。但也许你会发现Philip this简短而精彩的演示文稿,Philip Roberts很有帮助,这解释了事件循环的概念和JavaScript的异步处理。请注意,视频与node.js不相关,因为这些原则适用于所有JavaScript代码。