在node.js中,for循环和异步回调如何结合使用?

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

            }
        }
    });

我认为自从您发布这篇文章以来,Node对fs命名空间进行了一些同步功能的添加。 - jcollum
JavaScript 循环内部的闭包 - 简单实用的例子 - Bergi
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);

        }
    }
});

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

3
+1 对于使用.forEach方法的做法。这样做更加简单,避免了为每个迭代创建新的范围。 - Alnitak

0

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接