在Node.js中将变量传递给回调函数

9
我很新于Node技术,正尝试创建一个获取服务器信息的应用。但是我遇到了问题。我设置了一个配置对象(这将在未来通过事件动态更新),然后在函数中尝试访问此对象中的值。(请参见下面的代码)。
首先,我设置了变量:
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"]
        ]
    };
}

并初始化调用该函数

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

我不想使用全局变量,你们有没有其他解决方法?谢谢!=]

1个回答

13

由于异步执行的顺序,很多人会遇到这个陷阱。

你的for循环将从0到3进行循环,当'i'为4时退出。需要记住的困难部分是,你的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返回它们。相反,您需要传递自己的回调,并从执行回调中调用它。

更新

请注意,每次迭代拥有作用域的最简单方法是使用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);
        });
    }
}

1
非常感谢!我知道我必须在exec回调函数内部执行自己的回调,但现在我理解了作用域。非常感谢你的帮助! - Daniel Noel-Davies
这是个人习惯,但我喜欢使用不同的名称来表示内部的“i”变量,以便在一年后阅读时能够指出它是一个不同的变量。因此,内部函数看起来像 - 请原谅缺少格式 - (function(inner) {...console.log(config.daemons[inner]);})(i); - Mörre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接