通过重写一些我在C#中拥有的实用工具,我从中学习了很多有关Node.js的乐趣。我发现有些东西不是在Node.js中写的好主意,或者我完全错过了一个可以使之工作的概念。
该程序的目标:在文件目录中搜索包含符合某些条件的数据的文件。这些文件是XML压缩文件,目前我只是在寻找一个标签。这是我尝试过的(files
是文件名数组):
while (files.length > 0) {
var currentPath = rootDir + "\\" + files.pop();
var fileContents = fs.readFileSync(currentPath);
zlib.gunzip(fileContents, function(err, buff) {
if (buff.toString().indexOf("position") !== -1) {
console.log("The file '%s' has an odometer reading.", currentPath);
return;
}
});
if (files.length % 1000 === 0) {
console.log("%d files remain...", files.length);
}
}
当我写它的时候,我对此很紧张。从控制台输出中可以明显看出,所有gunzip操作都是异步的,并决定等待while循环完成。这意味着当我最终得到一些输出时,currentPath
它没有读取文件时的值,因此该程序无用。我没有看到使用zlip模块解压缩数据的同步方式。我没有找到一种存储上下文的方法(currentPath
会这样做),因此回调具有正确的值。我最初尝试使用流,将文件流管道传输到gunzip流,但是我遇到了类似的问题,因为所有的回调都在循环完成之后发生,并且丢失了有用的上下文。
这是漫长的一天,但我对如何组织这一点没有想法。循环是一个同步的事物,而我的异步事物取决于其状态。那很不好。我想念什么?如果未压缩文件,由于readFileSync(),这将很容易。
哇。我真的没想到根本没有答案。我陷入了时间紧缩的境地,但是我花了最后几天来研究Node.js,假设某些事情为什么像他们一样工作,并了解控制流。
因此,按原样的代码不起作用,因为我需要关闭以捕获的值currentPath
。Boy确实喜欢闭包和回调之类的Node.js。因此,应用程序的更好结构如下所示:
function checkFile(currentPath, fileContents) {
var fileContents = fs.readFileSync(currentPath);
zlib.gunzip(fileContents, function(err, buff) {
if (buff.toString().indexOf("position") !== -1) {
console.log("The file '%s' has an odometer reading.", currentPath);
return;
}
});
}
while (files.length > 0) {
var currentPath = rootDir + "\\" + files.shift();
checkFile(currentPath);
}
但是事实证明,这并不是一个Node,因为有太多同步代码。为了异步地做到这一点,我需要依靠更多的回调。该程序的结果比我预期的要长,因此为了简洁起见,我只会发布其中的一部分,但是它的前几位看起来像这样:
function checkForOdometer(currentPath, callback) {
fs.readFile(currentPath, function(err, data) {
unzipFile(data, function(hasReading) {
callback(currentPath, hasReading);
});
});
}
function scheduleCheck(filePath, callback) {
process.nextTick(function() {
checkForOdometer(filePath, callback);
});
}
var withReading = 0;
var totalFiles = 0;
function series(nextPath) {
if (nextPath) {
var fullPath = rootDir + nextPath;
totalFiles++;
scheduleCheck(fullPath, function(currentPath, hasReading) {
if (hasReading) {
withReading++;
console.log("%s has a reading.", currentPath);
}
series(files.shift());
});
} else {
console.log("%d files searched.", totalFiles);
console.log("%d had a reading.", withReading);
}
}
series(files.shift());
进行串行控制流程的原因是,如果我设置了明显的并行搜索,最终用完了进程内存,那可能是因为堆栈上有60,000个以上的缓冲区数据了:
while (files.length > 0) {
var currentPath = rootDir + files.shift();
checkForOdometer(currentPath, function(callbackPath, hasReading) {
//...
});
}
我可能可以将其设置为并行调度50个文件的批处理,并在完成后再等待50个文件。设置串联控制流程似乎同样容易。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句