node.js callback recebendo o valor inesperado para variável
-
18-09-2019 - |
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
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.
}