Pergunta

Eu tenho um loop for, e dentro dela uma variável é atribuído com var. Também no interior do circuito de um método é chamado o que requer uma chamada de retorno. Dentro da função de retorno de chamada que eu estou usando a variável do loop. Eu esperaria que de valor, dentro da função de retorno de chamada, seria o mesmo que era fora do retorno de chamada durante a iteração do loop. No entanto, ele sempre parece ser o valor do última iteração do loop.

Am I mal entendido escopo no JavaScript, ou há algo errado?

O programa em questão aqui é um aplicativo node.js que irá monitorar um diretório de trabalho para alterações e reiniciar o servidor quando ele encontra um. Vou incluir todo o código para os curiosos, mas o bit importante é a função 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();

A saída deste é:

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

Para aqueles do futuro: node.devserver.js

Foi útil?

Solução

Este é um comportamento perfeitamente normal. Seus retornos de chamada são executados em algum momento mais tarde (de forma assíncrona), mas ainda referenciar o alcance sua para circuito foi executado em. Todas as referências de retorno de chamada para arquivo terá, portanto, o último valor que foi conjunto de.

O que você quer fazer é criar um novo escopo função, atribuir o valor atual de arquivo a uma variável local e criar a chamada de retorno dentro desse âmbito.

    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.
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top