2009-12-09 7 views
7

Tengo un ciclo for, y dentro de él se asigna una variable con var. También dentro del ciclo se llama un método que requiere una devolución de llamada. Dentro de la función de devolución de llamada estoy usando la variable del ciclo. 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 ciclo. Sin embargo, siempre parece ser el valor de la última iteración del ciclo.node.js callback obtener un valor inesperado para la variable

¿No entiendo mal el alcance en JavaScript, o hay algo más?

El programa en cuestión aquí es una aplicación node.js que supervisará los cambios en un directorio de trabajo y reiniciará el servidor cuando encuentre uno. Incluiré todo el código para los curiosos, pero el bit 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(); 

El resultado de esto 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 aquellos del futuro:node.devserver.js

Respuesta

15

Este es un comportamiento perfectamente normal. Las devoluciones de llamada se ejecutan en algún momento posterior (de forma asíncrona) pero siguen haciendo referencia al ámbito en el que se ejecutó su para el bucle. Todas las referencias de devolución de llamada al archivo tendrán, por lo tanto, el último valor establecido.

Lo que se quiere hacer es crear un nuevo ámbito de la función, asigne el valor actual del 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. 
    } 
Cuestiones relacionadas