回调函数中for循环的回调函数

时间:2016-06-26 10:55:10

标签: javascript node.js asynchronous callback

我是Node.js的新手。在我研究Node.js时,我坚持与异步/同步相关的事情。我理解异步函数的逻辑和其他示例的回调。但是,我不理解下面的例子。我引自:http://code-maven.com/list-content-of-directory-with-nodejs

为什么以下代码无法正常运行?作者说它是由fs.stat()方法的第一个参数引起的。最后两个工作示例中显示了执行此操作的正确方法。我不理解工作和非工作示例之间的区别以及为什么第一个示例无法正常工作,最后两个示例正常工作。

var fs = require('fs');

if (process.argv.length <= 2) {
    console.log("Usage: " + __filename + " path/to/directory");
    process.exit(-1);
}

var path = process.argv[2];

fs.readdir(path, function(err, items) {
    for (var i=0; i<items.length; i++) {
        var file = path + '/' + items[i];
        console.log("Start: " + file);

        fs.stat(file, function(err, stats) {
            console.log(file);
            console.log(stats["size"]);
        });
    }
});

输出结果为:

$ node examples/node/list_dir_direct.js ~/work/code-maven.com/examples/

Start: /home/gabor/work/code-maven.com/examples//blocking-read-file.js
Start: /home/gabor/work/code-maven.com/examples//node_hello_world.js
Start: /home/gabor/work/code-maven.com/examples//node_hello_world_port.js
Start: /home/gabor/work/code-maven.com/examples//non-blocking-read-file.js
Start: /home/gabor/work/code-maven.com/examples//process_exit.js
Start: /home/gabor/work/code-maven.com/examples//raw_command_line_arguments.js
Start: /home/gabor/work/code-maven.com/examples//read_dir.js
Start: /home/gabor/work/code-maven.com/examples//stats.js

/home/gabor/work/code-maven.com/examples//stats.js
97
/home/gabor/work/code-maven.com/examples//stats.js
243
/home/gabor/work/code-maven.com/examples//stats.js
270
/home/gabor/work/code-maven.com/examples//stats.js
151
/home/gabor/work/code-maven.com/examples//stats.js
18
/home/gabor/work/code-maven.com/examples//stats.js
324
/home/gabor/work/code-maven.com/examples//stats.js
27
/home/gabor/work/code-maven.com/examples//stats.js
1382

调试打印输出按预期打印名称,但随后在fs.stat()的回调中,我们继续打印出相同的文件名。将结果与

的输出进行比较
$ ls -l ~/work/code-maven.com/examples/
total 64
-rw-r--r--  1 gabor  staff    97 Jan 29 14:26 blocking-read-file.js
-rw-r--r--  1 gabor  staff   243 Jan 27 12:34 node_hello_world.js
-rw-r--r--  1 gabor  staff   270 Jan 27 12:34 node_hello_world_port.js
-rw-r--r--  1 gabor  staff   151 Jan 29 14:26 non-blocking-read-file.js
-rw-r--r--  1 gabor  staff    18 Jan 31 08:24 process_exit.js
-rw-r--r--  1 gabor  staff    27 Jan 29 14:54 raw_command_line_arguments.js
-rw-r--r--  1 gabor  staff   324 Jan 31 15:26 read_dir.js
-rw-r--r--  1 gabor  staff  1382 Jan 31 10:45 stats.js

大小似乎与文件名匹配,因为它们的打印顺序与我们调用fs.stat()的顺序相同,但由于某种原因,文件变量的内容对于每个回调都是相同的。发生这种情况是因为文件变量只是一个简单的全局变量(从回调的角度来看),并且在第一次回调执行时,文件变量已经分配了目录中的最后一个条目。

以下代码可以正常使用。

var fs = require('fs');

if (process.argv.length <= 2) {
    console.log("Usage: " + __filename + " path/to/directory");
    process.exit(-1);
}

var path = process.argv[2];

fs.readdir(path, function(err, items) {
    for (var i=0; i<items.length; i++) {
        var file = path + '/' + items[i];

        console.log("Start: " + file);
        fs.stat(file, generate_callback(file));
    }
});

function generate_callback(file) {
    return function(err, stats) {
            console.log(file);
            console.log(stats["size"]);
        }
};

此外,以下代码也能正常工作。

var fs = require('fs');

if (process.argv.length <= 2) {
    console.log("Usage: " + __filename + " path/to/directory");
    process.exit(-1);
}

var path = process.argv[2];

fs.readdir(path, function(err, items) {
    for (var i=0; i<items.length; i++) {
        var file = path + '/' + items[i];

        console.log("Start: " + file);
        fs.stat(file, function(f) {
            return function(err, stats) {
               console.log(f);
               console.log(stats["size"]);
            }
        }(file));
    }
});

1 个答案:

答案 0 :(得分:0)

在第一个示例中,pass-by-reference有效。文件变量通过引用传递,因此回调函数获取文件变量的最后一个值并且工作不正确。 在第二个和第三个例子中,按值传递有效。文件变量按值传递,因此回调函数正确获取每个文件的名称。