2009-12-09 6 views
7

J'ai une boucle for, et à l'intérieur une variable est assignée avec var. Aussi à l'intérieur de la boucle, une méthode est appelée qui nécessite un rappel. À l'intérieur de la fonction de rappel, j'utilise la variable de la boucle. Je m'attendrais à ce que sa valeur, à l'intérieur de la fonction de rappel, soit la même qu'elle était en dehors du rappel pendant cette itération de la boucle. Cependant, il semble toujours être la valeur de dernière itération de la boucle. Suis-je mal comprendre la portée en JavaScript, ou y at-il quelque chose d'autre qui ne va pas?node.js callback obtenant une valeur inattendue pour la variable

Le programme en question ici est une application node.js qui surveillera un répertoire de travail pour les changements et redémarrera le serveur quand il en trouve un. Je vais inclure tout le code pour les curieux, mais le bit important est la fonction 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 sortie de c'est:

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 

Pour ceux de l'avenir:node.devserver.js

Répondre

15

Ce comportement est parfaitement normal. Vos rappels sont exécutés plus tard (de manière asynchrone) mais référencent toujours la portée de votre boucle pour. Toutes les références de rappel au fichier auront donc la dernière valeur à laquelle il a été défini.

Ce que vous voulez faire est de créer un nouveau champ d'application de la fonction, affecter la valeur actuelle de fichier à une variable locale et créer le rappel dans cette portée.

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. 
    } 
Questions connexes