如何确保两个setInterval()不会相互影响?

时间:2013-05-16 07:51:13

标签: javascript jquery

我有2个setInterval函数(好吧,伙计们,对不起,我认为里面的代码可能是多余的,会让问题变得本地化:/但无论如何,这里是:

$('#armStatus').click(function(){
  armingloop = setInterval(function () {
  if ($checkbox.is(':checked ')) {
    $.post('/request', {
      key_pressed: "arming_status"
    }).done(function (reply) {
      $arm.empty().append("<h3>The Arming Status is " + reply + "</h3>").show();
      $arm.show();
    });
  } else {
    $arm.hide();
  }
}, 3000);
});

$('#monitor').click(function () {
  bigloop = setInterval(function () {
  var checked = $('#status_table tr [id^="monitor_"]:checked');
  if (checked.index() === -1 || checked.length === 0) {
    clearloop(bigloop);
    $('#monitor').button('enable');
  } else {
    //$('#monitor').button('enable'); //enable the monitor button
    (function loop(i) {
      //monitor element at index i
      monitoring($(checked[i]).parents('tr'));
      //delay of 3 seconds
      setTimeout(function () {
        //when incremented i is less than the number of rows, call loop for next index
        if (++i < checked.length) loop(i);
      }, 3000);
    }(0)); //start with 0
  }
}, index * 3000); //loop period

});

 function clearloop(loopname){
          bigloop= window.clearInterval(loopname);
     }

两者都将由不同的选择器触发。我观察到,当bigloop被激活,并且armingloop稍后也被激活时,monitoring中的状态更新功能bigloop会受到影响(例如状态回复是被错误的元素捕获。)

请注意,我也有setTimer

我的问题是,如何确保任何2 setInterval被隔离并且不会相互影响?

3 个答案:

答案 0 :(得分:3)

你根本不能,因为他们不保证订单。它们与其他事件(包括重绘等)一起被添加到事件队列中,并且首先调用它们。

更好的实现是在你的主循环中抛出你的监听器正在监听的CustomEvent

简化为:

// global flag for monitoring
var isMonitoring = true,
    armingloop;

// the function we use to update monitor.
// This will be called every time we send an event
function updateMonitor(e) {
    /* ... update ... */
    // ie. e.detail.mydata 
}

// Start listening to 'monitor' event. If received, call
// the function above (only reference the function).
window.addEventListener('monitor', updateMonitor, false);

// The main loop. Self-triggering for loop by calling
// setTimeout.
// Do the stuff you need and then, if monitor is
// enabled create an event and dispatch (send) it.
function loop() {

    /* ... main stuff ... */

    // do we monitor? 
    if (isMonitoring) {

        // something need to be updated on monitor so
        // create an event
        var myEvent = new CustomEvent('monitor', {
            detail: {
                /* here you can provide needed data for monitor */
                "mydata": data /*, other data */
            },
            /* If you don't need to send any data in particular,
               just leave detail empty like this:
               detail: {},
            */
            bubbles: false,
            cancelable: true
        });

        // send event to anyone who listens..
        window.dispatchEvent(myEvent);
    }

    //here you can use a use a flag to stop the loop,
    //f.ex. if 'isLooping' === true then setTimeout...
    armingloop = setTimeout(loop, 3000);
}

function toggleMonitor() {
    // Call this from the toggle button, or modify to
    // reflect checkbox-status etc...
    isMonitoring = !isMonitoring;
}

//start everything:
loop();

我将示例从setInterval更改为setTimeout以避免堆叠/阻止。还要记住,Javascript是单线程的(除了一些与此无关的例外)。因此setTimeout是更好的选择(从循环内部调用它)。

答案 1 :(得分:1)

  

如何确保任何2个setIntervals被隔离并且不会相互影响?

可变范围

确保所涉及的所有变量都是正确的范围,并避免将任何变量添加到全局范围,除非它完全不可避免(这不应该是这种情况)。这意味着每当您声明任何变量时,您都希望使用var关键字。

如果你的变量被正确地限定为各自的setInterval调用,那么即使你使用了相同的变量名,也不存在影响另一个变量值的危险。

检查您的逻辑

如果您在两个页面中查询并修改相同的元素集,那么它们就不能独立,因为其中一个元素的更改将反映在另一个元素的下一个执行中一。任何共享逻辑,全局变量的使用等都是引入问题的潜在候选者。

基本上你正在寻找两者之间的任何重叠,然后(希望)消除它。如果不能被删除,那么你的两个setIntervals就无法被隔离,你要么必须接受这两者是联系的,要么找到解决问题的另一种方法。

答案 2 :(得分:0)

如何触发间隔?

也许您可以尝试将它们称为例如点击功能:

$('<ELEMENT>').click( function() {
    setInterval(function(){

    },3000);
});

$('<ELEMENT>').click( function() {
    setInterval(function () {

             var checked = $('#status_table tr [id^="monitor_"]:checked');
            if (checked.index()===-1 ||checked.length===0){
                clearloop(bigloop);
                $('#monitor').button('enable');
            }else{
                    //$('#monitor').button('enable'); //enable the monitor button
                    (function loop(i) {                           
                        //monitor element at index i
                        monitoring($(checked[i]).parents('tr'));
                        //delay of 3 seconds
                        setTimeout(function () {
                            //when incremented i is less than the number of rows, call loop for next index
                            if (++i < checked.length) loop(i);
                        }, 3000);
                    }(0)); //start with 0
            }                            
        }, index*3000); //loop period
});