1

我正在制作一个简单的脚本来读取 node.js 中的 nginx 服务器状态我不认为我的问题与 node.js 本身有关,但更多的是我如何使用 setInterval() 函数的问题。

我不想粘贴所有代码,因为这会使阅读有点混乱。当您运行此代码时,您会看到:

pre-Timer for web25
pre-Timer for web26
pre-Timer for web27
pre-Timer for web28
pre-Timer for web29
Timer for web29
Fetch host? web29
Timer for web29
Fetch host? web29
Timer for web29
Fetch host? web29
Timer for web29
Fetch host? web29
Timer for web29
Fetch host? web29

如您所见,计时器仅使用循环的最后一个主机。不知何故,它没有将变量复制到 setInterval 范围。

我究竟做错了什么?

部分代码:

var http = require('http');

StatsNginxMapper.prototype = {

nginxServers: new Object(),
mysql: null,
mysqlClient: null,
statsDb: 'serverstats',
userMapper: null,

init: function() {
    this.mysql = require('mysql');
    this.mysqlClient = /* mysql stuff */;

    this.collectData();
},

setUserMapper: function(mapper) {
    this.userMapper = mapper;
},

collectData: function() {
    this.collectServers();
},

collectServers: function() {

    var self = this;
    var server = null;

    /* Normally this is done through MySQL, but for now lets do it manually */

    server = new StatsNginxServer();
    server.setHost('web25');
    this.nginxServers['web25'] = server;

    server = new StatsNginxServer();
    server.setHost('web26');
    this.nginxServers['web26'] = server;

    server = new StatsNginxServer();
    server.setHost('web27');
    this.nginxServers['web27'] = server;

    server = new StatsNginxServer();
    server.setHost('web28');
    this.nginxServers['web28'] = server;

    server = new StatsNginxServer();
    server.setHost('web29');
    this.nginxServers['web29'] = server;

    this.loopServers();

},

loopServers: function() {

    for(var host in this.nginxServers) {
        var nginxServer = this.nginxServers[host];

        if(nginxServer.hasTimer()) continue;

        var self = this;
        console.log('pre-Timer for ' + host);

        var timerId = setInterval(function() {

            console.log('Timer for ' + host);

            self.getData(host);

            }, 2000);

        nginxServer.setTimer(timerId);

    }

},

getData: function(host) {
    console.log('Fetch host? ' + host);
},

}

4

2 回答 2

1

将 loopServers 函数更改为:

loopServers: function() {

    for(var host in this.nginxServers) {            
        var nginxServer = this.nginxServers[host];

        if(nginxServer.hasTimer()) continue;

        var self = this;
        console.log('pre-Timer for ' + host);
        (function(host, nginxServer, self) {
            var timerId = setInterval(function() {    
                console.log('Timer for ' + host);   
                self.getData(host);   
            }, 2000);

            nginxServer.setTimer(timerId);
        })(host, nginxServer, self);
    };
}

这将围绕 setInterval 代码创建一个闭包,该闭包将保留该点的变量值。

有关关闭的信息

于 2012-04-10T09:19:43.863 回答
1

问题是在间隔上运行的函数在调用时使用范围内的变量执行。这意味着,对每个间隔调用“可见”的主机是循环中的最后一个(在您的情况下为 web29)。

解决方案是确保运行的函数始终在范围内具有正确的函数。一种方法是:

var timerId = setInterval(function(host) {
    return function() {
        console.log('Timer for ' + host);
        self.getData(host);
    }
}(host), 2000);

在这里,我们创建一个新函数,它返回您希望运行的函数。我们在创建时立即运行该函数,并传递当时的“主机”值。这样,执行日志记录的函数将始终拥有创建时范围内的主机。

我试图简化语言以使其更清晰,但我不确定我是否成功了。如果您阅读了我写的内容,希望它应该看得清楚。

于 2012-04-10T09:28:52.227 回答