2012-04-10 29 views
1

我做一個簡單的腳本讀出的node.js nginx的服務器狀態,我不認爲我的問題與node.js的本身做的,但更多的問題與我如何使用setInterval()函數。參數傳遞給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); 
}, 

}

回答

1

的問題是,其上的間隔運行的功能,執行與在範圍上時,它調用的變量。這意味着,對於每個插入呼叫「可見」的主機是循環中的最後一個(在你的案例中,web29)。

解決方案是確保運行的函數始終有合適的範圍。這樣做的一種方法是:

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

在這裏,我們創建一個新函數,它返回您希望運行的函數。我們在創建時立即運行該函數,並在那時通過「主機」的值。這樣,執行日誌記錄的功能將始終具有創建時處於範圍內的主機。

我試圖簡化語言,以使其更清晰,但我不知道我成功了。如果你仔細閱讀我寫的內容,希望它能看得清楚。

+0

謝謝大衛,我也喜歡你的解決方案。我會看到哪一個對我來說更有效率 – 2012-04-10 09:44:28

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代碼封閉,以保障這個點的變量值。

Information about closures

+0

謝謝!工程:) 有趣的是,我用匿名函數,並打它工作得很好,但沒有嘗試過他們兩個! – 2012-04-10 09:42:29

相關問題