node.js обратный вызов, получающий неожиданное значение для переменной

StackOverflow https://stackoverflow.com/questions/1875754

  •  18-09-2019
  •  | 
  •  

Вопрос

У меня есть цикл for, и внутри него переменной присваивается значение var.Также внутри цикла вызывается метод, который требует обратного вызова.Внутри функции обратного вызова я использую переменную из цикла.Я бы ожидал, что его значение внутри функции обратного вызова будет таким же, каким оно было вне обратного вызова во время этой итерации цикла.Однако, кажется, что это всегда значение из Последние итерация цикла.

Я неправильно понимаю область видимости в JavaScript, или что-то еще не так?

Программа, о которой здесь идет речь, представляет собой node.js приложение, которое будет отслеживать изменения в рабочем каталоге и перезапускать сервер, когда он их обнаружит.Я включу весь код для любопытных, но важным моментом является функция 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();

Результатом этого является:

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

Для тех, кто из будущего: node.devserver.js

Это было полезно?

Решение

Это совершенно нормальное поведение.Ваши обратные вызовы выполняются в какой-то более поздний момент (асинхронно), но все еще ссылаются на область вашего для цикл был запущен.Все ссылки обратного вызова на файл таким образом, будет иметь последнее значение, на которое оно было установлено.

Что вы хотите сделать, это создать новую область действия функции, присвоить текущее значение файл к локальной переменной и создайте обратный вызов внутри этой области.

    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.
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top