在《Node.js in Action》一书中,有一个示例,目录“./text”中的文件受字数统计。我想问一下,所使用的闭包实际上是必然的还是只是风格问题。代码如下:
var fs = require('fs');
var completedTasks = 0;
var tasks = [];
var wordCounts = {};
var filesDir = './text';
function checkIfComplete() {
completedTasks++;
if (completedTasks == tasks.length) {
for (var index in wordCounts) {
console.log(index + ': ' + wordCounts[index]);
}
}
}
function countWordsInText(text) {
var words = text
.toString()
.toLowerCase()
.split(/\W+/)
.sort()
for (var index in words) {
var word = words[index];
if (word) {
wordCounts[word] = (wordCounts[word]) ? wordCounts[word] + 1 : 1;
}
}
}
// My question is on the use of closure below
fs.readdir(filesDir, function(err, files) {
if (err) throw err;
for (var index in files) {
var task = (function(file) {
return function() {
fs.readFile(file, function(err, text) {
if (err) throw err;
countWordsInText(text);
checkIfComplete();
});
}
})(filesDir + '/' + files[index]);
tasks.push(task);
}
for (var task in tasks) {
tasks[task]();
}
});
本书中使用此代码来演示并行控制流的本质。我的问题是为什么代码要经历这种看似扭曲的构建闭包然后调用它们的详细阐述(抱歉,哈哈,这里是新手)? (我指的是任务中的每个任务。)
这与我认为更自然的情况有什么不同吗?
fs.readdir(filesDir, function(err, files) {
if (err) throw err;
tasks = files; // Just to make sure the check for completion runs fine.
for (var index in files) {
var file = files[index];
fs.readFile(filesDir + '/' + file, function(err, text) {
if (err) throw err;
countWordsInText(text);
checkIfComplete();
});
}
});
它不是仍然是异步的并且像之前的代码一样“并行”吗?
这里可以避免关闭。需要关闭以避免臭名昭著的closure-in-loop如果传递给 fs.readFile
的回调访问循环变量或从中派生的内容,就会发生这种情况。因为这样,当调用回调时,循环变量的值将是分配给它的最后一个值。
你的做法没问题。我没有尝试完全清理代码或使其能够适应错误,但我会这样做:
var fs = require('fs');
var wordCounts = Object.create(null);
var filesDir = './text';
function countWordsInText(text) {
var words = text
.toString()
.toLowerCase()
.split(/\W+/)
.sort();
for (var index in words) {
var word = words[index];
if (word) {
wordCounts[word] = (wordCounts[word]) ? wordCounts[word] + 1 : 1;
}
}
}
fs.readdir(filesDir, function(err, files) {
if (err) throw err;
var total = files.length;
var completedTasks = 0;
for (var index in files) {
fs.readFile(filesDir + '/' + files[index], function(err, text) {
if (err) throw err;
countWordsInText(text);
completedTasks++;
if (completedTasks === total) {
for (var index in wordCounts) {
console.log(index + ': ' + wordCounts[index]);
}
}
});
}
});
我是一名优秀的程序员,十分优秀!