Change setInterval value dynamically


I want to change interval value of setInterval dynamically. I'm struggling due to presence of a loop in setInterval callback function. I have seen too many questions on stackoverflow. But there is no any solution which can help me. If anyone know answer then please explain with an example. Thank You. Here is my code.

<html>
<head>
    <script type="text/javascript">
        var speed = 10;
        function updateSlider(slideAmount) {
            speed = slideAmount;
        }
        function load() {
            downloadUrl("points.xml", function (data) {
                /* code */
                abc();
            });
            function abc() {
                function track() {
                    /* code */
                    downloadUrl("points.xml", function (data) {
                        var xml = data.responseXML;
                        var points = xml.documentElement.getElementsByTagName("point");
                        var i = 0;
                        setInterval(function () {
                            if (i != points.length) {
                                alert(speed);
                            }
                            i++;
                        }, 100 * speed);
                    });
                }
                track();
            }
        }
        function downloadUrl(url, callback) {
            var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest;
            request.onreadystatechange = function () {
                if (request.readyState == 4) {
                    request.onreadystatechange = doNothing;
                    callback(request, request.status);
                }
            };
            request.open('GET', url, true);
            request.setRequestHeader("Content-type", "text/xml");
            request.send(null);
        }
        function doNothing() {
        }
    </script>
</head>
<body onload="load();">
    <div id="slider">
        5% <input id="slide" type="range" min="1" max="20" step="5" value="10" onchange="updateSlider(this.value)" /> 200%
    </div>
    <div id="chosen">10</div>
</body>

The trick is to not use setInterval, and to use setTimeout in a loop instead.

setInterval reads the timing value you give it once, schedules based on this timing, and forgets about it. The only thing you can do is clearInterval(myInterval) if you've assigned your interval to a variable like myInterval.

setTimeout is much the same, except we can use it to manually loop on the same function. Manually looping allows us to change the timing of setTimeout after each timeout.

Here's a quick example. Moving the slider to the left makes the ticking faster, and to the right, slower.

DEMO

var timing = 250,
    i = 0,
    output = document.getElementById('output');

function loop() {
  i++;
  output.innerHTML = i;
  window.setTimeout(loop, timing);
}

document.querySelector('input[type="range"]').addEventListener('change', function (e) {
  timing = parseInt(this.value);
});

loop();
<input type="range" min="100" max="500" value="250" />
<div id="output"></div>

As a side note: Using this pattern is almost always a better option than using setInterval. setInterval runs the chance that your function execution could take longer than the duration of the interval. This never happens with a looping setTimeout if you call setTimeout last in the function.

Documentation:


This is a version without setInterval i always use:

function timer()
{
    var timer = {
        running: false,
        iv: 5000,
        timeout: false,
        cb : function(){},
        start : function(cb,iv,sd){
            var elm = this;
            clearInterval(this.timeout);
            this.running = true;
            if(cb) this.cb = cb;
            if(iv) this.iv = iv;
            if(sd) elm.execute(elm);
            this.timeout = setTimeout(function(){elm.execute(elm)}, this.iv);
        },
        execute : function(e){
            if(!e.running) return false;
            e.cb();
            e.start();
        },
        stop : function(){
            this.running = false;
        },
        set_interval : function(iv){
            clearInterval(this.timeout);
            this.start(false, iv);
        }
    };
    return timer;
}

Usage:

var timer_1 = new timer();
timer_1.start(function(){
    //magic here
}, 2000, false);

var timer_2 = new timer();
timer_2.start(function(){
    //more magic here
}, 3000, true);

//change the interval
timer_2.set_interval(4000);

//stop the timer
timer_1.stop();

The last parameter of the start function is a boolean if the function needs to be run at 0.

You can also find the script here: https://github.com/Atticweb/smart-interval


Here's another easy way to dynamically update interval.

var intv_sec = 1500; // Initial interval in milliseconds
var speed = 1.5; // Multiplier

function chk_fn(){
  // Your code here
  console.log(intv_sec);
  
  
  // Reset and update interval
  clearInterval(chkh);
  intv_sec = intv_sec*speed;
  chkh = setInterval(chk_fn, intv_sec);
}

var chkh = setInterval(chk_fn, intv_sec);