在这种情况下使用window.setTimeout()和window.setInterval()

时间:2013-04-30 21:56:41

标签: javascript settimeout clearinterval

这可能是一个新问题,但...... 最近,我一直在使用window.setTimeout来对父函数进行递归调用,这会对服务器进行ajax轮询。

function connectToVM(portal) {
    //making the ajax call here....
   if(response.responseText !== "")
     {
    windowInterval = window.setTimeout(function() {
        connectToVM(portal)
    }
    , 4000);
   }
  }

windowInterval是我的全局变量。

if(!checkIfChartExists()) {
  window.clearInterval(windowInterval);
}

现在,我不是在这里使用变量,而是知道我可以简单地将function传递给clearTimeout,但这也会导致所有其他间隔停止:(

我这样做的原因是服务器只有在有响应时才会超时。 我的方案是,我有一个更新每个超时间隔的图表。 AFAIK,当我们设置间隔时,有一个特定的值设置为变量(如果设置为变量)。因此,当我打印我的变量时(每次调用超时函数时),我得到一些唯一的int值。

我有很多标签,许多标签可以有相同的图表..它只使用之前触发的相同间隔。 现在我只有一张图表..但是我有很多图表可以显示哪些类型相同。说规格图。

我还必须在当前所选标签中没有图表时清除超时 - 我正在做的事情。 所以我打算只做一个函数,它只是通过将所需的参数传递给这个函数来调用服务器。

但是为了进行民意调查,我正在使用上面提到的window.setTimeout。 这适用于1个图表。 现在,我尝试添加1个图表,使用不同的参数集来轮询服务器,我将需要使用一些不同的setTimeout函数,它的id与早期触发的超时的id不同。

我还必须考虑如果第一个图表已经存在,则超时已经被触发并且必须保持运行。 所以,现在我必须触发第二次超时。 但这里没有second timeout

我想知道是否有任何替代方法,因为我无法预测运行时会有多少图表。

Question 1 : Can we flood our browser with many timeout's?

Question 2 : How to get the id of that particular timeout, so that I can clearTimeout(id) on it?

Question 3 : Since we can't assign / make variables on the fly, how to set / make such a data structure which can hold such a pointer to the particular chart's index / id.. so that we can easily get hold of it and clear it.

Question 4 : Is this the only way we can poll the server(via AJAX) if we have to poll continually?

最后,我发现这是我在这里发布的一个非常complex的问题。但我相信我会从论坛中找到有关该方法的一些有用信息。 我没有太多经验在JS中完成所有这些工作,但是感谢任何帮助!


更新

抱歉,我必须在这里发布我的代码..但我使用Extjs来获取我的图表portlet。函数connectToVM的代码是:

function connectToVM(portalId, host, port, user, passwd, db) {
      try{
        if(Ext.getCmp(portalId)) 
        {
            var gaugeChartForTitle = Ext.getCmp(portalId);

            if(typeof portalOriginalTitle === 'undefined')
                portalOriginalTitle = gaugeChartForTitle.title;

            var gaugeChartDiv = document.getElementById(portalId);

            Ext.Ajax.request({
                      url: "/connectToVM?" +
                            Ext.urlEncode({
                                host: host,
                                port: port,
                                user: user,
                                passwd: passwd,
                                db: db
                            }),
                      method: 'GET',
                      success: function (response, options) {

                          if(response.responseText !== "")
                          {
                              gaugeChartDiv.style.background = "";

                              gaugeChartForTitle.setTitle(portalOriginalTitle);

                              console.log("Virtual Machine at "+ host +" :  BUSY % : "+response.responseText);

                              virtualMachineStore.loadData(generateVirtualMachineData(response.responseText)); //Setting the data1 value of the store and loading it for display!

                              windowInterval = window.setTimeout(function() {
                                  connectToVM(portalId, host, port, user, passwd, db)
                                }
                              , 4000);
                          } 
                          else 
                          {
                              windowInterval = window.setTimeout(function() {
                                  connectToVM(portalId, host, port, user, passwd, db)
                                }
                              , 10000); //Retry every 10 seconds to check if the connection is established!

                              gaugeChartDiv.style.background = "red";
                              gaugeChartForTitle.setTitle(portalOriginalTitle +" - Connection Failure. Reconnecting!");
                          }
                      },
                      failure: function ( result, request) { 
                     }
              });
         }
             }
             catch(err) {
             }
         }

现在,我使用它来触发我的功能:

function setWindowIntervalForVM(portalId) {
       //console.log("isIntervalActivated inside setWindowIntervalForVM() : "+isIntervalActivated);
       if(!isIntervalActivated) {
           connectToVM(portalId, host, port, user, pwd, db);
       }
    }

   function checkIfWindowIntervalIsActivated(portal) {
       if(!isIntervalActivated) {
            setWindowIntervalForVM(portal.id);
            isIntervalActivated = true;
        } else {
            window.clearInterval(windowInterval);
            windowInterval = null;
            isIntervalActivated = false;
        }
   }

所以checkIfWindowIntervalIsActivated()是我在这些场景中调用的父函数调用:

1)每当新创建Gauge Chart时..我会触发此调用并拥有boolean isIntervalActivated,如果它是false,则会触发服务器调查

2)所以现在如果我已经在标签1中有图表(因为用户选择了它),我现在更改为没有它的tab 2。所以我只需将isIntervalActivated设置为true即可停止轮询。 This is handled for 1 chart。现在的问题是,如果我想要创建此函数re-usable,请说我想再删除一个相同type但具有不同server parameters的图表进行民意调查,如何使用相同的windowInterval变量,它具有我的第一个图表的触发超时值。 P.S:它所做的每个ajax请求的值都会发生变化。所以没有1 single值:(

3)我在其他标签中没有相同类型的chart时停止投票。这很有道理。现在,每当用户放入新的portlet /页面加载时,我都会缓存所有的portlet,从而拉动所有用户配置的portlet。在这样的case中,我必须触发所有charts' ajax调用..每次轮询到其configured destination。现在,我不知道会有多少图表,就像我的函数名称一样,我正在查询VM。因此,如果用户使用VM1,则会切换到VM2,依此类推。

因此,为许多类似的图表创建相同的功能是绝对不可能的。 所以我只是想检查一下我是否能re-use同时出现这个问题,或者采取完全different方法解决这个问题:( :(

我希望现在有点清楚,如果不是,我可以更多地解释我的情况。 如果需要,请问我更多问题:) 再次感谢!

2 个答案:

答案 0 :(得分:1)

  1. var x = window.setTimeout(...); window.clearTimeout(x);
  2. 将其作为数据属性存储在活动选项卡上,对象上的属性或全局变量中。许多不同的方式。示例代码可以更容易回答这个问题。

  3. 根据您的意见:

    var windowInterval;
    function connectToVM(portal) {
        if(windowInterval)window.clearTimeout(windowInterval);
        windowInterval = window.setTimeout(function() { ... }, 4000);
    }
    

答案 1 :(得分:1)

如果我理解正确并且您尝试同时支持多个图表更新,我会从保持connectToVM()闭包内的图表数据切换到显式的图表对象数组并使用单个间隔更新所有图表。

如下所示(将其视为伪代码):

var charts = [
  // an array of chart objects, see addChart()
];

function addChart() {
  // when you need to add or remove a chart, update the charts object, like this:
  charts.push({
    update: updateChart,
    nextUpdateTime: null, // or Date.now() if you don't care about old browsers.
    chartData: {host: ..., port: ..., user: ..., passwd: ..., db: ...,
                originalTitle: ..., portalId: ...},
  });
  restartUpdates();
}

var activeInterval = null;
function restartUpdates() {
  if (activeInterval) {
    clearInterval(activeInterval);
  }
  activeInterval = setInterval(updateCharts, 5000);
}

// updates all active charts
function updateCharts() {
  var now = new Date().getTime();
  for (var i = 0; i < charts.length; i++) {
    var chart = charts[i];
    if (chart.nextUpdateTime !== null && chart.nextUpdateTime < now) {
      chart.nextUpdateTime = null; // chart.update() will re-set this
      try {
        chart.update(chart);
      } catch(e) {
        // handle the error
      }
    }
  }

// update a single chart.
// @param |chart| is an item from the |charts| array.
function updateChart(chart) {
  // ...same as your connectToVM() using properties from chart.chartData...
  Ext.Ajax.request(
    // ...
      success: function (response, options) {
        // ...same as before...
        // ...but instead of re-setting the timeout:
        //   windowInterval = window.setTimeout(function() {
        //       connectToVM(portalId, host, port, user, passwd, db)
        //     }
        //   , 4000);
        // ...update the chart's nextUpdateTime:
        chart.nextUpdateTime = (new Date().getTime()) + 4000;
      }
  );
}

下面的初步答案

感谢您提出详细的问题!感觉你错过了一些非常明显的问题#2/3,但是如果没有看到更多的代码,很难说清楚具体是什么。你能发布一个更完整,更简单的例子来证明你想要解决的问题吗?也许更改伪代码中的活动选项卡的函数处理会有所帮助,如下所示:

function selectTab(tabID) {
  // ...activate tab #tabID in the GUI...
  if (tabID == 1) {
    // there's chart #1 on tab #1, need to stop any active timeouts and start a new one 
    connectToVM("chart #1");
  } else if (tabID == 2) {
    // no charts on tab #2.. need to stop any active timeouts
  } else if (tabID == 3) {
    // ...
  }
}

我不明白的一件事是,在任何时候都需要更新单一图表吗?

另外,您是否了解A re-introduction to JavaScript中提到的概念,特别是对象?

至于问题:

  • 1:是的,应该避免太多的超时(数千秒可能会使CPU变热并且浏览器缓慢),虽然我更担心服务器,它必须处理来自多个客户端的请求。
  • 2/3:见上文。
  • 4:Comet页面列出了许多基本AJAX轮询(服务器发送事件,长轮询,websockets)的替代方案,但我稍后会担心这一点。