...

View Full Version : Calling a method every second...



DaveRich
03-12-2012, 05:03 AM
So I'm new around here, and to web dev in general, but I've got a (hopefully) short question.

I am trying to call a function (nextMonth()) every second from the time that the cycle method gets called, until it is called again. As of now I am trying to use setInterval, (and I previously tried with setTimeout and using a callback argument but maybe I wasn't doing that properly).

The problem is that after running the cycle() method for 5 or 6 seconds, the entire browser freezes up and you have to kill it and restart it.

Here is my code as of now:



function cycle()
{
if(CYCLEINT != null) //STOP THE CYCLE LOOP
{
window.clearInterval(CYCLEINT);
CYCLEINT = null;
document.getElementById("cycle").innerHTML = "Cycle Months";
}

else //LOOP IS NOT RUNNING, INITIATE AND CONTINUE INTERVAL.
{
CYCLEINT = self.setInterval("nextMonth()", 1000);
document.getElementById("cycle").innerHTML = "Pause";
}
}


function prevMonth()
{
var dVal = $( ".slider" ).slider( "option", "value");

if(dVal > 1)
{
dVal--;
$( ".slider" ).slider( "option", "value", dVal );
refresh();
}
}

function nextMonth()
{
var dVal = $( ".slider" ).slider( "option", "value");

if(dVal < dateMax)
{
dVal++;
$( ".slider" ).slider( "option", "value", dVal );
refresh();
}

if(CYCLEINT != null && dVal >= dateMax)
{
cycle();
}
}

rnd me
03-12-2012, 05:59 AM
remove

if(CYCLEINT != null && dVal >= dateMax)
{
cycle();
}

DaveRich
03-12-2012, 04:04 PM
That if-statement there checks to make sure there is still room on the end of the slider bar and that the date value can be incremented.

Without that the loop will never end.

rnd me
03-12-2012, 05:24 PM
That if-statement there checks to make sure there is still room on the end of the slider bar and that the date value can be incremented.

Without that the loop will never end.

well with it, it will never stop spawning new loops...

glenngv
03-12-2012, 06:01 PM
You have two loops running. Replace setInterval with setTimeout.

And also don't pass string to the setTimeout/setInterval. Pass a function pointer instead.


setTimeout(nextMonth, 1000);

If you have parameter to the function, then it should be:


setTimeout(function(){ nextMonth(param1, param2); }, 1000);

DaveRich
03-12-2012, 07:49 PM
I tried using setTimeout instead, but what happens is it looks like nothing is working and then the slider is all of a sudden at the end.

Would it be possibly to split the "cycle" method into two seperate methods? and then change the method call similar to how you change innerHTML?

blaze4218
03-14-2012, 12:20 AM
Here's a real simple loop constructor that comes in handy for these cases, there's not much in the way of error detection, but I like it.


var Loop = function(myFunct){

var loop = this;

var rate = 1000 ,
code = myFunct ,
paused = false,

run = function () {

clearTimeout(loop.Cycle);

if (code) {

if(!paused)
code();

loop.Cycle = setTimeout(run , rate);

}

};

loop['resume'] = function () {
paused = false;
} ,

loop['pause'] = function () {
paused = true;
} ,

loop['kill'] = function () {
code = false;
} ,

loop['speed'] = function (r) {
(r&&(typeof r=='number')&&r>0)&&(rate = r);
return rate;
} ,

loop['init'] = function () {
if(!loop.Cycle&&code)
run();
};
};
/* Minified for your convenience ;)
var Loop=function(f){function e(){clearTimeout(a.a);b&&(c||b(),a.a=setTimeout(e,d))}var a=this,d=1E3,b=f,c=!1;a.resume=function(){c=!1};a.pause=function(){c=!0};a.kill=function(){b=!1};a.s peed=function(a){a&&"number"==typeof a&&0<a&&(d=a);return d};a.init=function(){!a.a&&b&&e()}};
*/

I whipped up the following test page for you to familiarize yourself with the function:


<div id="red" style="position:absolute;top:20px;left:20px;border:1px solid red;padding:20px">
<button onclick="red.init()">init</button>
<button onclick="red.pause()">pause</button>
<button onclick="red.resume()">resume</button>
<button onclick="red.speed(red.speed()+500)">slower</button>
<button onclick="red.speed(red.speed()-500)">faster</button>
<button onclick="red.kill();this.innerHTML='dead';">kill</button>
<br>
<h1>Red</h1>
</div>
<div id="blue" style="position:absolute;top:20px;left:400px;border:1px solid blue;padding:20px">
<button onclick="blue.init()">init</button>
<button onclick="blue.pause()">pause</button>
<button onclick="blue.resume()">resume</button>
<button onclick="blue.speed(blue.speed()+500)">slower</button>
<button onclick="blue.speed(blue.speed()-100)">faster</button>
<button onclick="blue.kill();this.innerHTML='dead';">kill</button>
<br>
<h1>Blue</h1>
</div>
<script>
var Loop=function(f){function e(){clearTimeout(a.a);b&&(c||b(),a.a=setTimeout(e,d))}var a=this,d=1E3,b=f,c=!1;a.resume=function(){c=!1};a.pause=function(){c=!0};a.kill=function(){b=!1};a.s peed=function(a){a&&"number"==typeof a&&0<a&&(d=a);return d};a.init=function(){!a.a&&b&&e()}};

var red_code = function(){
document.getElementById('red').innerHTML+='<br>looped ' + red.speed()
}
var blue_code = function(){
document.getElementById('blue').innerHTML+='<br>looped ' + blue.speed()
}

var red = new Loop(red_code);
red.speed(5000);

var blue = new Loop(blue_code);
blue.speed(1000);

</script>

So if I understand your algorithm (and I'm not sure I do) you would do the following


var Loop=function(f){function e(){clearTimeout(a.a);b&&(c||b(),a.a=setTimeout(e,d))}var a=this,d=1E3,b=f,c=!1;a.resume=function(){c=!1};a.pause=function(){c=!0};a.kill=function(){b=!1};a.s peed=function(a){a&&"number"==typeof a&&0<a&&(d=a);return d};a.init=function(){!a.a&&b&&e()}};

function cycle(){

if(CYCLEINT != null) //STOP THE CYCLE LOOP
{
CYCLEINT = null;
nextMonthCycle.pause();
document.getElementById("cycle").innerHTML = "Cycle Months";
}

else //LOOP IS NOT RUNNING, INITIATE AND CONTINUE INTERVAL.
{
CYCLEINT = 'somevalue'; //Not sure if you need this anymore...
nextMonthCycle.resume();
document.getElementById("cycle").innerHTML = "Pause";
}

};

function prevMonth()
{
var dVal = $( ".slider" ).slider( "option", "value");

if(dVal > 1)
{
dVal--;
$( ".slider" ).slider( "option", "value", dVal );
refresh();
}
}
var nextMonthCycle;
function nextMonth()
{
nextMonthCycle = new Loop(function()
{
var dVal = $( ".slider" ).slider( "option", "value");

if(dVal < dateMax)
{
dVal++;
$( ".slider" ).slider( "option", "value", dVal );
refresh();
}

if(CYCLEINT != null && dVal >= dateMax)
{
cycle(); //you can call this as many times as you want, and it won't spawn a new loop
}
});
nextMonthCycle.init();
}

I'm not really sure if I integrated it properly with your code... If I could see more of the code...

Either way- you don't want to enable the chance for a loop to be called from within itself, that is what is crashing your browser. The Loop constructor only allows a loop to be created once, preventing any accidental loop feedback logic. From there you can pause and resume at will.

DaveRich
03-14-2012, 07:53 PM
Thanks blaze4218,

I had to make a few changes to get the code to run, for example I kept getting the following error:

nextMonthCycle is not defined in the current scope.

I think this was because the variable doesn't get defined until the nextMonth() function was called, so calling cycle() first calls it to fail.

So in order to fix this I just added the following two lines of code just above the declaration for nextMonth so they get executed on page load.



nextMonth();
nextMonthCycle.pause();


That seems to work, however the browser still freezes and crashes when it runs the loop.

Here is a link to the source for the entire page: http://jsfiddle.net/Xh8ZU/

DaveRich
03-14-2012, 08:45 PM
I found out a solution to this problem, as it turns out the loop wasn't the problem, the problem was the jQuery package (qTip) that I was using for tooltips.

I just had to make sure that the qTip's weren't updating content while the loop was running, as it was queuing all the qTip updates until the loop finished and then try and update everything at once.

Works now.

Thanks for all your help!



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum