Pregunta

Tengo un bucle, y en el interior se le asigna una variable con var. También dentro del bucle de un método se llama que requiere una devolución de llamada. Dentro de la función de devolución de llamada que estoy usando la variable del bucle. Yo esperaría que su valor, dentro de la función de devolución de llamada, sería el mismo que estaba fuera de la devolución de llamada durante esa iteración del bucle. Sin embargo, siempre parece ser el valor de la última iteración del bucle.

¿Estoy mal entendido alcance en JavaScript, o hay algo más mal?

El programa en cuestión aquí es una aplicación Node.js que supervisará un directorio de trabajo para los cambios y reiniciar el servidor cuando se encuentra uno. Voy a incluir todo el código para los curiosos, pero la parte importante es la función 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();

La salida de este es:

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 los del futuro: node.devserver.js

¿Fue útil?

Solución

Este es un comportamiento perfectamente normal. Sus devoluciones de llamada se ejecutan en algún momento posterior (asíncrona), pero aún hacen referencia al alcance de su de bucle se ejecuta en. Todas las referencias de devolución de llamada a archivo , por tanto, tener el último valor que fue ajustado a.

Lo que se quiere hacer es crear un nuevo ámbito de la función, asigne el valor actual de archivo a una variable local y crear la llamada de retorno dentro de ese á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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top