21

我是 JavaScript 和 node.js 的新手。我想遍历一个目录并将所有文件统计信息(而不是其他目录)添加到一个数组中。正如您在下面看到的,我的代码存在问题,因为在 for 循环完成后可能会调用回调,因此在回调方法中使用“i”变量将不起作用。但是代码应该如何看起来才能使下面的代码片段起作用?它与闭包有关吗?

感谢帮助!

    fs.readdir(SYNCDIR, function(err1, files) {
        var filesOnly = [];

        if(!err1) {

            for(var i = 0; i < files.length; i++) {

                var imgFilePath = SYNCDIR + '/' + files[i];
                fs.stat(imgFilePath, function(stat){

                    if (stat.isFile()){
                        filesOnly[i] = stat; // This will not be correct since the for-loop has finished
                    }
                });

            }
        }
    });
4

3 回答 3

32

您需要使用闭包是正确的。您应该将循环的内容包装for在一个自调用函数中,以保留i每次迭代的值。

fs.readdir(SYNCDIR, function(err1, files) {
    var filesOnly = [];

    if(!err1) {

        for(var i = 0; i < files.length; i++) {

            (function(i) {
                var imgFilePath = SYNCDIR + '/' + files[i];
                fs.stat(imgFilePath, function(stat){
                    if (stat.isFile()){
                        filesOnly[i] = stat;
                    }
                });
            })(i);

        }
    }
});
于 2011-09-01T10:55:05.107 回答
10

一种方法是重写循环的内部结构以使用闭包:

fs.readdir(SYNCDIR, function(err1, files) {
    var filesOnly = [];
    if(!err1) {
        for(var i = 0; i < files.length; i++) {
            (function(index) {
                var imgFilePath = SYNCDIR + '/' + files[index];
                fs.stat(imgFilePath, function(stat){
                    if (stat.isFile()){
                        filesOnly[index] = stat;
                    }
                });
            })(i);
        }
    }
});

一个更好看的例子,使用 Array.prototype.forEach 实现相同的效果:

fs.readdir(SYNCDIR, function(err1, files) {
    var filesOnly = [];
    if(!err1) {
        files.forEach(function(file, i) {
            var imgFilePath = SYNCDIR + '/' + file;
            fs.stat(imgFilePath, function(stat){
                if (stat.isFile()){
                    filesOnly[i] = stat;
                }
            });
        });
    }
});
于 2011-09-01T10:58:28.450 回答
0

或者使用新的线程模块(https://github.com/robtweed/Q-Oper8),然后您可以更简单地使用线程子进程中的标准同步编码来完成所有这些工作,因为它们只处理一个用户的请求一次。

告别异步逻辑和嵌套回调!

于 2011-09-01T12:17:14.003 回答