我想对任意大的文件集执行一些任意昂贵的工作。我想实时报告进度,然后在处理完所有文件后显示结果。如果没有与我的表达式匹配的文件,我想抛出一个错误。
想象一下编写一个测试框架来加载所有测试文件,执行它们(不按特定顺序),实时报告进度,然后在所有测试完成后显示汇总结果。
用阻塞语言(例如 Ruby)编写这段代码非常简单。
事实证明,我在节点中执行这个看似简单的任务时遇到了麻烦,同时也真正利用了异步的、基于事件的 IO。
我的第一个设计是按顺序执行每个步骤。
- 加载所有文件,创建要处理的文件集合
- 处理集合中的每个文件
- 处理完所有文件后报告结果
这种方法确实有效,但对我来说似乎不太正确,因为它会导致我的程序中计算成本更高的部分等待所有文件 IO 完成。这难道不是 Node 旨在避免的那种等待吗?
我的第二个设计是处理每个文件,因为它是在磁盘上异步找到的。为了争论,让我们想象一个看起来像这样的方法:
eachFileMatching(path, expression, callback) {
// recursively, asynchronously traverse the file system,
// calling callback every time a file name matches expression.
}
这个方法的消费者看起来像这样:
eachFileMatching('test/', /_test.js/, function(err, testFile) {
// read and process the content of testFile
});
虽然这种设计感觉像是一种使用 IO 的非常“节点”的方式,但它存在两个主要问题(至少在我推测的错误实现中):
- 我不知道什么时候所有的文件都被处理了,所以我不知道什么时候组装和发布结果。
- 因为文件读取是非阻塞的,并且是递归的,所以我正在努力了解如何知道是否没有找到文件。
我希望我只是做错了什么,并且其他人使用一些相当简单的策略来使第二种方法起作用。
尽管这个例子使用了一个测试框架,但我还有很多其他项目遇到了同样的问题,我想任何人都会编写一个相当复杂的应用程序来访问节点中的文件系统。