yvonnezoe
yvonnezoe

Reputation: 7407

How to make sure two setInterval() will not affect each other?

I have 2 setInterval function (okay guys, sorry, I thought the code inside may be redundant and will make the question become localized :/ but anyway, here it is:

$('#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);
});

and

$('#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);
     }

Both will be triggered by a different selector. I observe that when the bigloop is activated, and armingloop is also activated at a later time, the status update function monitoring in my bigloop is affected (e.g. status reply is captured by wrong element.)

Note that I have a setTimer as well.

My question here is, how can i make sure any 2 setIntervals are isolated and will not affect each other?

Upvotes: 2

Views: 2690

Answers (3)

Niek Nijland
Niek Nijland

Reputation: 772

How are the intervals triggered?

Maybe you can try to call them in for example a click function:

$('<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
});

Upvotes: 0

Anthony Grist
Anthony Grist

Reputation: 38345

How can I make sure any 2 setIntervals are isolated and will not affect each other?

Variable scope

Make sure that all of the variables involved are correctly scoped, and avoid adding any to the global scope unless it's completely unavoidable (this shouldn't be the case). This means you'll want to be using the var keyword whenever you declare any variables.

If your variables are correctly scoped to their respective setInterval calls then there's no danger of one affecting values in the other, even if you've used the same variable names.

Check your logic

If you're querying, and then modifying, the same set of elements on the page in both of them then they can't be independent, since changes in one of them will then be reflected in the next execution of the other one. Any shared logic, any use of global variables, etc. are all potential candidates for issues to be introduced.

Essentially you're looking for any overlap between the two, and then (hopefully) eliminating that. If it can't be eliminated then your two setIntervals can't be isolated, and you either have to accept that the two are linked or find another approach to solving the problem.

Upvotes: 1

user1693593
user1693593

Reputation:

You simply can't as they have no guarantee of order. They are added to an event queue together with other events (incl. repaints etc.), and which ever comes first is called.

A better implementation would be in your main loop to throw a CustomEvent which your monitor is listening to.

Simplified:

// 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();

I changed the example a bit from setInterval to setTimeout to avoid stacking/blocking. Also keep in mind that Javascript is single-threaded (with a few exceptions that are not relevant here). For this reason setTimeout is a better choice (call it from inside the loop).

Upvotes: 3

Related Questions