彼得里昂的答案是伟大的/正确的。我将稍微扩展一下,并提出一种使用承诺和co
以及嵌套/循环异步性的不同方法。
/* Script to count all lines of a file */
const co = require("co");
// Promisifed fs -- eventually node will support this on its own
const fs = require("mz/fs");
const rootDir = 'files/';
// Recursivey count the lines of all files in the given directory and sum them
function countLines(directory) {
// We can only use `yield` inside a generator block
// `co` allows us to do this and walks through the generator on its own
// `yield` will not move to the next line until the promise resolves
//
// This is still asynchronous code but it is written in a way
// that makes it look synchronized. This entire block is asynchronous, so we
// can `countLines` of multiple directories simultaneously
return co(function*() {
// `files` will be an array of files in the given directory
const files = yield fs.readdir(directory);
// `.map` will create an array of promises. `yield` only completes when
// *all* promises in the array have resolved
const lines = yield files.map(file => countFileLines(file, directory));
// Sum the lines of all files in this directory
return lines.reduce((a, b) => a + b, 0);
});
}
function countFileLines(file, directory) {
// We need the full path to read the file
const fullPath = `${directory}/${file}`;
// `co` returns a promise, so `co` itself can be yielded
// This entire block is asynchronous so we should be able to count lines
// of files without waiting for each file to be read
return co(function*() {
// Used to check whether this file is a directory
const stats = yield fs.stat(fullPath);
if (stats.isDirectory()) {
// If it is, recursively count lines of this directory
return countLines(fullPath);
}
// Otherwise just get the line count of the file
const contents = yield fs.readFile(fullPath, "utf8");
return contents.split("\n").length - 1;
});
}
co(function*() {
console.log(yield countLines(rootDir));
})
// All errors propagate here
.catch(err => console.error(err.stack));
请注意,这只是一个例子。可能已经有库来计算目录中的文件行数,并且确实存在能够简化递归读取/文件匹配的库。
你必须在异步函数 –
的回调中完成所有工作。我知道这一点。我如何确保请求处理程序在所有回调完成之前都不会返回(不通过)。 –
有很多不同的方法来做到这一点。我会建议与ES7 transpilation +异步/等待。如果你不想经历麻烦,那么[co](https://github.com/tj/co)/'yield'就相当接近。我仍然建议使用内置于节点的[Promises](https://github.com/petkaantonov/bluebird),但我链接的蓝鸟库可能会提示不支持promise的库。我强烈推荐Promises ...我认为它们可以简化异步流程。 [异步](https://github.com/caolan/async)也很受欢迎。最后,你可以推出自己的。 –