Передача переменных в обратные вызовы в Node.js - PullRequest
9 голосов
/ 06 ноября 2011

Я довольно новичок в узле и пытаюсь создать что-то, что получит некоторую информацию о сервере. Но вот моя проблема. Я настраиваю объект конфигурации (со временем он будет динамически обновляться при возникновении событий), а затем позже, в функции, я пытаюсь получить доступ к значению в этом объекте. (См. Код ниже)

Итак, во-первых, я настроил свои переменные:

var util            = require('util'),
    child           = require('child_process'),
    config          = {};

, который работает хорошо. Затем я загружаю свой конфиг:

function loadConfig( )
{
    // Add some code for auto-loading of args
    config = {
        "daemons": [
            ["Apache", "apache2"],
            ["MySQL",  "mysqld"],
            ["SSH", "sshd"]
        ]
    };
}

и init, вызывающий функцию

loadConfig();

После этого я запускаю проверку на демонах.

function getDaemonStatus( )
{
    for(var i=0; i<config.daemons.length; i++)
    {

        child.exec( 'ps ax -o \'%c %P\' | awk \'{if (($2 == 1) && ($1 == "\'' +
            config.daemons[i][1] + '\'")) print $0}\'',
            function( error, stdout, stderr )
        {

            console.log(config.daemons[i]);
        });
    }
}

Ответ, который я получаю:

undefined
undefined
undefined

Я действительно не хочу использовать переменную GLOBAL, так что вы, ребята, можете придумать другой способ решения моей проблемы?

Спасибо! =]

1 Ответ

13 голосов
/ 06 ноября 2011

Это ошибка, с которой сталкивается множество людей из-за асинхронного порядка выполнения.

Ваш цикл for будет выглядеть как 0-3, а затем завершится, когда 'i', очевидно, равно четырем.Трудно запомнить, что ваш обратный вызов для exec не запустится сразу.Он запускается только после запуска процесса, и к тому времени, когда это произойдет, цикл for будет выполнен.

Это означает, что, по сути, все три раза, когда выполняется ваша функция обратного вызова, вы, по сути, делаете это:

console.log(config.daemons[4]);

Вот почему он печатает 'undefined'.

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

function getDaemonStatus( ) {
    for(var i=0; i<config.daemons.length; i++) {
        (function(i) {

             child.exec( 'ps ax -o \'%c %P\' | awk \'{if (($2 == 1) && ($1 == "\'' +
                config.daemons[i][1] + '\'")) print $0}\'',
                function( error, stdout, stderr ) {

                console.log(config.daemons[i]);
            });

        })(i);
    }
}

Также я вижу, что ваша функция называется 'getDaemonStatus'.Просто помните, что, поскольку этот обратный вызов exec является асинхронным, это также означает, что вы не можете собрать результаты каждого обратного вызова, а затем вернуть их из getDaemonStatus.Вместо этого вам нужно будет передать свой собственный обратный вызов и вызвать его изнутри вашего обратного вызова exec.

Обновлено

Обратите внимание, что самый простой способ получить область за одну итерацию - этоиспользуйте forEach, например

function getDaemonStatus( ) {
    config.daemons.forEach(function(daemon, i){
         child.exec( 'ps ax -o \'%c %P\' | awk \'{if (($2 == 1) && ($1 == "\'' +
            daemon[1] + '\'")) print $0}\'',
            function( error, stdout, stderr ) {

            console.log(daemon);
        });
    }
}
...