代码之家  ›  专栏  ›  技术社区  ›  Craig McQueen

node.js回调获取变量的意外值

  •  7
  • Craig McQueen  · 技术社区  · 16 年前

    我有一个for循环,其中一个变量被赋予var。在循环中,一个方法被调用,它需要回调。在回调函数内部,我使用的是循环中的变量。我希望它的值,在回调函数内部,与循环迭代期间在回调外部的值相同。然而,它似乎总是来自 最后的 循环的迭代。

    我是误解了JavaScript中的作用域,还是有其他问题?

    这里讨论的程序是node.js应用程序,它将监视工作目录的更改,并在找到更改后重新启动服务器。我将为好奇者提供所有代码,但重要的一点是parse_file_list函数。

    var posix = require('posix');
    var sys = require('sys');
    var server;
    var child_js_file = process.ARGV[2];
    var current_dir = __filename.split('/');
    current_dir = current_dir.slice(0, current_dir.length-1).join('/');
    
    var start_server = function(){
        server = process.createChildProcess('node', [child_js_file]);
        server.addListener("output", function(data){sys.puts(data);});
    };
    
    var restart_server = function(){
        sys.puts('change discovered, restarting server');
        server.close();
        start_server();
    };
    
    var parse_file_list = function(dir, files){
        for (var i=0;i<files.length;i++){
            var file = dir+'/'+files[i];
            sys.puts('file assigned: '+file);
            posix.stat(file).addCallback(function(stats){
                sys.puts('stats returned: '+file);
                if (stats.isDirectory())
                    posix.readdir(file).addCallback(function(files){
                        parse_file_list(file, files);
                    });
                else if (stats.isFile())
                    process.watchFile(file, restart_server);
            });
        }
    };
    
    posix.readdir(current_dir).addCallback(function(files){
        parse_file_list(current_dir, files);
    });
    
    start_server();
    

    其输出为:

    file assigned: /home/defrex/code/node/ejs.js
    file assigned: /home/defrex/code/node/templates
    file assigned: /home/defrex/code/node/web
    file assigned: /home/defrex/code/node/server.js
    file assigned: /home/defrex/code/node/settings.js
    file assigned: /home/defrex/code/node/apps
    file assigned: /home/defrex/code/node/dev_server.js
    file assigned: /home/defrex/code/node/main_urls.js
    stats returned: /home/defrex/code/node/main_urls.js
    stats returned: /home/defrex/code/node/main_urls.js
    stats returned: /home/defrex/code/node/main_urls.js
    stats returned: /home/defrex/code/node/main_urls.js
    stats returned: /home/defrex/code/node/main_urls.js
    stats returned: /home/defrex/code/node/main_urls.js
    stats returned: /home/defrex/code/node/main_urls.js
    stats returned: /home/defrex/code/node/main_urls.js
    

    对于来自未来的人: node.devserver.js

    1 回复  |  直到 16 年前
        1
  •  15
  •   Michiel Kalkman Sanath    16 年前

    这是完全正常的行为。您的回调在稍后的某个时间点(异步)执行,但仍引用 对于 循环正在运行。所有回调引用 文件 因此将具有它设置为的最后一个值。

    您要做的是创建一个新的函数作用域,为 文件 到局部变量 在该范围内创建回调。

        for (var i=0;i<files.length;i++){
            var file = dir+'/'+files[i];
            (function() {
                var file_on_callback = file;
                sys.puts('file assigned: '+ file_on_callback);
                posix.stat(file_on_callback).addCallback(function(stats){
                    sys.puts('stats returned: '+ file_on_callback);
                    if (stats.isDirectory())
                        posix.readdir(file_on_callback).addCallback(function(files){
                            parse_file_list(file_on_callback, files);
                        });
                    else if (stats.isFile())
                        process.watchFile(file_on_callback, restart_server);
                });
            })(); // This creates and executes a new function with its own scope.
        }
    
    推荐文章