How to stop a setTimeout loop?

JavascriptCssExtjsSettimeout

Javascript Problem Overview


I'm trying to build a loading indicator with a image sprite and I came up with this function

function setBgPosition() {
   var c = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
       Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c<numbers.length)
		{
            setTimeout(run, 200);
		}else
		{
			setBgPosition();
		}
    }
    setTimeout(run, 200);
}

so the out put is looks like this

http://jsfiddle.net/TTkre/

I had to use setBgPosition(); inside else to keep this running in a loop so now my problem is how to stop this loop once I want [load finished]?

Javascript Solutions


Solution 1 - Javascript

setTimeout returns a timer handle, which you can use to stop the timeout with clearTimeout.

So for instance:

function setBgPosition() {
    var c = 0,
        timer = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c >= numbers.length) {
            c = 0;
        }
        timer = setTimeout(run, 200);
    }
    timer = setTimeout(run, 200);

    return stop;

    function stop() {
        if (timer) {
            clearTimeout(timer);
            timer = 0;
        }
}

So you'd use that as:

var stop = setBgPosition();
// ...later, when you're ready to stop...
stop();

Note that rather than having setBgPosition call itself again, I've just had it set c back to 0. Otherwise, this wouldn't work. Also note that I've used 0 as a handle value for when the timeout isn't pending; 0 isn't a valid return value from setTimeout so it makes a handy flag.

This is also one of the (few) places I think you'd be better off with setInterval rather than setTimeout. setInterval repeats. So:

function setBgPosition() {
    var c = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c >= numbers.length) {
            c = 0;
        }
    }
    return setInterval(run, 200);
}

Used like this:

var timer = setBgPosition();
// ...later, when you're ready to stop...
clearInterval(timer);

All of the above notwithstanding, I'd want to find a way to make setBgPosition stop things itself, by detecting that some completion condition has been satisfied.

Solution 2 - Javascript

I know this is an old question, I'd like to post my approach anyway. This way you don't have to handle the 0 trick that T. J. Crowder expained.

var keepGoing = true;

function myLoop() {
    // ... Do something ...
    
    if(keepGoing) {
        setTimeout(myLoop, 1000);
    }
}

function startLoop() {
    keepGoing = true;
    myLoop();
}

function stopLoop() {
    keepGoing = false;
}

Solution 3 - Javascript

SIMPLIEST WAY TO HANDLE TIMEOUT LOOP

function myFunc (terminator = false) {
	if(terminator) {
		clearTimeout(timeOutVar);
	} else {
		// do something
		timeOutVar = setTimeout(function(){myFunc();}, 1000);
	}
}	
myFunc(true); //  -> start loop
myFunc(false); //  -> end loop

Solution 4 - Javascript

You need to use a variable to track "doneness" and then test it on every iteration of the loop. If done == true then return.

var done = false;

function setBgPosition() {
    if ( done ) return;
    var c = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
        if ( done ) return;
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c<numbers.length)
        {
            setTimeout(run, 200);
        }else
        {
            setBgPosition();
        }
    }
    setTimeout(run, 200);
}

setBgPosition(); // start the loop

setTimeout( function(){ done = true; }, 5000 ); // external event to stop loop

Solution 5 - Javascript

var myVar = null;

if(myVar)
   clearTimeout(myVar);

myVar = setTimeout(function(){ alert("Hello"); }, 3000);

Solution 6 - Javascript

Try something like this in case you want to stop the loop from inside the function:

let timer = setInterval(function(){
  // Have some code to do something

  if(/*someStopCondition*/){ 
    clearInterval(timer)
  }
},1000);

You can also wrap this inside a another function, just make sure you have a timer variable and use clearInterval(theTimerVariable) to stop the loop

Solution 7 - Javascript

As this is tagged with the extjs tag it may be worth looking at the extjs method: http://docs.sencha.com/extjs/6.2.0/classic/Ext.Function.html#method-interval

This works much like setInterval, but also takes care of the scope, and allows arguments to be passed too:

function setBgPosition() {
	var c = 0;
	var numbers = [0, -120, -240, -360, -480, -600, -720];
	function run() {
	   Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
		if (c<numbers.length){
			c=0;
		}
	}
	return Ext.Function.interval(run,200);
}

var bgPositionTimer = setBgPosition();

when you want to stop you can use clearInterval to stop it

clearInterval(bgPositionTimer);

An example use case would be:

Ext.Ajax.request({
	url: 'example.json',

	success: function(response, opts) {
		clearInterval(bgPositionTimer);
	},

	failure: function(response, opts) {
		console.log('server-side failure with status code ' + response.status);
		clearInterval(bgPositionTimer);
	}
});

Solution 8 - Javascript

I am not sure, but might be what you want:

var c = 0;
function setBgPosition()
{
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run()
    {
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c<=numbers.length)
        {
            setTimeout(run, 200);
        }
        else
        {
            Ext.get('common-spinner').setStyle('background-position', numbers[0] + 'px 0px');
        }
    }
    setTimeout(run, 200);
}
setBgPosition();

Solution 9 - Javascript

In the top answer, I think the if (timer) statement has been mistakenly placed within the stop() function call. It should instead be placed within the run() function call like if (timer) timer = setTimeout(run, 200). This prevents future setTimeout statements from being run right after stop() is called.

EDIT 2: The top answer is CORRECT for synchronous function calls. If you want to make async function calls, then use mine instead.

Given below is an example with what I think is the correct way (feel to correct me if I am wrong since I haven't yet tested this):

const runSetTimeoutsAtIntervals = () => {
	const timeout = 1000 // setTimeout interval
	let runFutureSetTimeouts // Flag that is set based on which cycle continues or ends

	const runTimeout = async() => {
		await asyncCall() // Now even if stopRunSetTimeoutsAtIntervals() is called while this is running, the cycle will stop
		if (runFutureSetTimeouts) runFutureSetTimeouts = setTimeout(runTimeout, timeout)
	}

	const stopRunSetTimeoutsAtIntervals = () => {
		clearTimeout(runFutureSetTimeouts)
		runFutureSetTimeouts = false
	}

	runFutureSetTimeouts = setTimeout(runTimeout, timeout) // Set flag to true and start the cycle
	return stopRunSetTimeoutsAtIntervals
}

// You would use the above function like follows.
const stopRunSetTimeoutsAtIntervals = runSetTimeoutsAtIntervals() // Start cycle
stopRunSetTimeoutsAtIntervals() // Stop cycle

EDIT 1: This has been tested and works as expected.

Solution 10 - Javascript

When the task is completed and you can display the task (image in your case), on the next refresh don't send the javascript. If your server is using PHP.

<?php if (!$taskCompleted) { ?>
<script language="javascript">
setTimeout(function(){
   window.location.reload(1);
}, 5000);
</script>
<?php } ?>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGihan LasitaView Question on Stackoverflow
Solution 1 - JavascriptT.J. CrowderView Answer on Stackoverflow
Solution 2 - JavascriptThimoKlView Answer on Stackoverflow
Solution 3 - JavascriptVALIKHANView Answer on Stackoverflow
Solution 4 - JavascriptNeil EssyView Answer on Stackoverflow
Solution 5 - JavascriptMahdi BashirpourView Answer on Stackoverflow
Solution 6 - JavascriptOyebolaView Answer on Stackoverflow
Solution 7 - JavascriptTheoView Answer on Stackoverflow
Solution 8 - JavascriptPritomView Answer on Stackoverflow
Solution 9 - JavascriptphilosopherView Answer on Stackoverflow
Solution 10 - JavascriptSenthilView Answer on Stackoverflow