2011-08-06 53 views
3
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读取阵列。Node.js的:在回调

console.log(result);#2将在第三次迭代后记录填充了所需值的result对象。

我认为这与Node.js/JavaScript回调的异步特性有关。如果我不了解JavaScript变量作用域和异步方法是如何工作的,请原谅我,我都是新手。

回答

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

迄今为止看起来不错。尽管这个解决方案结合了嵌套功能,但我还没有完全确信,但这仍然是一个合理的解决方案。干杯! – Daniel

+0

@thejh什么是“pending”在回调中有正确值的保证? – Praveen

-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 
    }); 
}); 
+0

错误。这不是一个for循环。 – thejh

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不会阻止这些值,所以之后的值将与异步操作完成之前的值相同。

+0

这是完全合理的,但是使用'fs.readdirSync()'也行不通。 – Daniel

0

它有回调做。在

fs.readdir('./' + dirname, function(err, res) { 
    if (err) throw err; 
    result[dirname] = res; 
    // #2 
}); 

传入的函数是一个回调,当目录被完全读取时执行。由于它是异步的,fs.readdir()在之前返回该函数实际执行。

所以基本上,你的forEach完成后,你有3个函数等待作为回调(每个目录一个)执行。在继续执行之前,代码不会等待回调发生,因此如果在读取目录之前达到#1,它将在回调执行并适当修改之前记录结果对象。

你可以使用fs.readdirSync来代替,但是只要这对你的应用程序没有坏处,如果这段代码暂时被阻塞了/这个代码不会无限制地阻塞并拖延你的程序。如果你需要它保持异步,看看jh的答案。

+1

不是+1,因为在很多情况下,你真的应该警告'fs.readdirSync'是一个坏主意。 – thejh

+0

好点。我编辑它 – shelman

2

我认为这与 Node.js/JavaScript回调的异步性质有关。

是的,这可能是为什么当您尝试在#1输出result变量的内容时,它是空的。在#1运行时,数据还没有被提取,因为在#2处执行readdir的回调会发生“提取”操作。我建议查看一下answer中所述的一些关于异步范例的资源,以获得回调和异步编程如何工作的更大/更好的图片。

+0

小心。并非所有的回调都会始终异步执行。 – bmeck

+0

谢谢,我阅读了所有“Node.js中的控制流”系列。好资源! – Daniel