var result = { controllers: [], views: [], models: [] };
var dirs = ['controllers', 'views', 'models'];
dirs.forEach(function(dirname) {
fs.readdir('./' + dirname, function(err, res) {
if (err) throw err;
result[dirname] = res;
// #2
});
});
// #1
在这段代码中,console.log(result);
运行在#1(见上文),将记录初始化的空控制器,视图和模型数组。但是,我需要循环来填充数组,并通过fs
读取相应的文件名。
console.log(result);
#2将在第三次迭代后记录填充了所需值的result
对象。
我认为这与Node.js / JavaScript回调的异步性质有关。如果我不理解JavaScript变量范围和异步方法是如何工作的,请原谅我,我对此都是新手。
答案 0 :(得分:2)
这样做:
var result = { controllers: [], views: [], models: [] };
var dirs = ['controllers', 'views', 'models'];
var pending = 0;
dirs.forEach(function(dirname) {
pending++;
fs.readdir('./' + dirname, function(err, res) {
pending--;
if (err) throw err;
result[dirname] = res;
if (pending===0) goOn();
});
});
function goOn() {
// #1
}
答案 1 :(得分:2)
我认为这与异步性质有关 Node.js / JavaScript回调。
是的,这可能就是为什么当您尝试在#1输出result
变量的内容时,它是空的。在#1运行时,数据尚未被提取,因为“提取”动作发生在#{1}}的回调#2处。我建议查看本answer中所述的有关异步范例的一些资源,以便更好/更好地了解回调和异步编程的工作原理。
答案 2 :(得分:0)
对于对措辞感到困惑的人,这里是每个目录中带有'1'文件的示例的输出:
~/Documents/$ node test.js
{ controllers: [], views: [], models: [] } 1
{ controllers: [], views: [ '1' ], models: [] } 2
{ controllers: [ '1' ], views: [ '1' ], models: [] } 2
{ controllers: [ '1' ],
views: [ '1' ],
models: [ '1' ] } 2
这是因为进入文件系统需要进行异步操作。因此,由于Node不会阻止值,因此将与异步操作完成之前相同。
答案 3 :(得分:0)
它确实与回调有关。在
fs.readdir('./' + dirname, function(err, res) {
if (err) throw err;
result[dirname] = res;
// #2
});
传入的函数是一个回调函数,它在完全读取目录时执行。由于它是异步的,因此fs.readdir()在函数实际执行之前返回。
所以基本上,在你的forEach完成之后,你有3个函数等待作为回调执行(每个目录一个)。代码不会在继续执行之前等待回调发生,所以如果在读取目录之前达到#1,它将在回调执行之前记录结果对象并适当地修改它。
您可以改为使用fs.readdirSync,但是如果此代码短暂阻止,则不会对您的应用程序造成不利影响/此代码无法无限期阻塞并阻止您的程序。如果你需要它保持异步,请查看你的答案。
答案 4 :(得分:-1)
我相信,如果dirname在第一个函数返回后发生变化,那么该值就是这样做的。要解决这个问题,只需将dirname复制到第二个函数调用的范围内;
dirs.forEach(function(dirn) {
var dirname = dirn; // make a copy here
fs.readdir('./' + dirname, function(err, res) {
if (err) throw err;
result[dirname] = res;
// #2
});
});