September 24, 2002
The Dark Side Of setInterval()

I just came across a nasty "feature" of the setInterval function which almost gives me mystical feelings. This is not for the weak hearted. We'll be entering an area of phantom functions and lost pointers:

Start the example and read on.

We have the following setup:

Movieclip "MAIN" is a simple container, its purpose is to load additional movieclips into other levels. I would call this a standard setup which occurs more than once in Flash history.

Movieclips "A", "B" and "C" are subclips that could work also standalone, so they contain all the functionality they need. (Real life example: Flash experiments that get loaded into the presentation area)

Now imagine that Movieclip "A" uses a setInterval call to trigger a counter. This counter runs until you press the stop button which cancels the interval. (This is a simple example, so we press the start button only once, okay?) Fine. Start. Stop. On. Off. Well, this gets boring after a while so let's see what the other movies have to offer. Let's load movieclip "B" into the same _level.

Ooops, we have forgotten to cancel the interval...

Well, whatever, one interval more or less will not hurt our performance. But what's this? The counter keeps counting! It looks like the "setCounter()" function still gets called. Oh how stupid that we used the same function name as in Movie "Q". But wait a minute... In this clip setCounter should count down not up. But the numbers are going up! So this is not the new function setCounter at work, but the old one. But didn't we replace the movie on _level1 completely by loading in the new clip?

But the magic continues... Lets load Movie "C". This one is almost identical to "A" except that it counts down if you press start. Hmmm.. the counter is still counting up. I wonder what happens if I click on "Start" now? This should finally replace that evil phantom interval, shouldn't it?

Press... Oh..... The counter has stopped. Yeah! Winner! The phantom is dead! Ye... Wait. Did I say it stopped? Shouldn't it run backwards? Let's try the "Stop" button. Uaaaaa! Run for your life! The phantom 's on us! the counter goes up again. So all that happened was that we have one version of "setCounter()" counting up and another one, its zombie brother counting up.

So what to we learn? Always clear all your intervals behind you.

But one question remains: where lives that phantom function? And how can I kill it if something like that happens?

Posted at September 24, 2002 11:40 AM | Further reading
Comments

When you pass a function to an interval it has no scope - it always exists until the interval is cancelled. The reference passed to setInterval is the reference that stops the function from being garbage-collected. Overwriting the function with another of the same name will have no effect because the function is called by reference and not by name.

In the second usage of setInterval, you can pass a string name for the function. That would allow the function to be overridden by subsequent definitions.

Posted by: Peter Hall on September 24, 2002 06:31 PM

You can extend/over-write the functionality of setInterval to have a scope and an id, so that you can have a method such as this.clearAllIntervals(), you could also then extend/over-write the loadMovie method to call the this.clearAllIntervals() method when the loadMovie method is executed, thus solving your problem.

Just a fix!

Posted by: Guy Watson on September 27, 2002 07:17 PM

How about using an event model based on setInterval which runs as a global monitor and automatically removes dead objects from the _listeners array. Here is an example:
--------------------------------------------------

_global.pbBroadcaster = new Object();

//You set the frame rate in typical flash fashion..
//This function coverts it to milliseconds for set interval
pbBroadcaster.setFps = function(fps){
this.fps = 1000/fps;
}//End function

//Returns the global fps of the movie
pbBroadcaster.getFps = function(fps){
return this.fps;
}//End function

pbBroadcaster.addListener = function(obj){
if(typeof(this._listeners) == "undefined") this._listeners = new Array();
var i, g;
i = this._listeners.length;
g = new Array(); //Array to contain good listeners
while(i--){
if(typeof(this._listeners[i]) != "undefined") g.push(this._listeners[i]);
}//End while loop

this._listeners = g;
//Push in the new listener if it a good object
if(typeof(obj) != "undefined") this._listeners.push(obj);
}//End function

pbBroadcaster.removeListener = function(obj){
if(typeof(this._listeners) == "undefined") return;

var i, n;
i = this._listeners.length;
n = new Array(); //Array to contain new valid listeners
while(i--){
if(this.listeners[i] != obj){
if(typeof(this._listeners[i]) != "undefined") {
n.push(this._listeners[i]);
}//end if
}//End if
}//End while loop

this._listeners = n;
}//End function

pbBroadcaster.onEnterFrame=function() {
var i = this._listeners.length;
while(i--){
this._listeners[i].event();
}//End while loop
}//End function

pbBroadcaster.setFps(30); //set the global framerate of the movie at 30 fps
setInterval(pbBroadcaster, "onEnterFrame", pbBroadcaster.getFps());

//--------------------------------------------------

/*Example from http://www.actionscript.org/tutorials/intermediate/setInterval/index2.shtml*/
function Stock(name) {
this.name = name;
}
Stock.prototype.updateStockPrices = function() {
// Update code here
trace('Updating prices for '+this.name);
};
Stock.prototype.onEnterFrame=function() {
this.updateStockPrices();
}//End function

StratFlash = new Stock("Stratford Flash Products");
//Activate the object to listen to events..
pbBroadcaster.addListener(StratFlash);
//-------------------------------

Hi Peter :)

Posted by: Navneet Behal on November 19, 2002 07:03 PM

You have to clear your intervals BEFORE unloading any movie loaded into flash. If you don't they will hang around in mid-air and balls everything up.

Posted by: feisty on February 25, 2003 04:38 PM

Hi fellow flashers,
i'm strugling for days on this subject & this is actually the first post i encounter digging my problem.
However, I still canot get it solved.

The code i'm struggling with is:

// ****************************************
function stopContinue(id){
trace("********* -> " + id);
fade2(id);
delete id;
// delete fadetimer and set a time to wait before autoContinue
clearInterval(fadetimer);
trace("fadetimer == " + fadetimer);
clearInterval(timerInterval);
timerInterval = setInterval(startContinue, 4000);
}
function startContinue() {
trace("Time's up!");
// Stop the timer and restart fadetimer
clearInterval(timerInterval);
delete timerInterval
clearInterval(fadetimer);
fadetimer = setInterval(fade2,2200);
trace("fadetimer = " + fadetimer);
}
// ****************************************

This is an image show, laoded upon another movie, with 2 intervals: first is an interval that auto fades an img every some seconds.
When you click a thumbnail, it stops but after some seconds the 2nd interval triggers the 1st one again and clears itself. Well, that's the idea...

it looks so simple, but indeed intervals are not getting cleared :c

any help on this would be *very* welcome !

hope to hear from anyone
klikfabriek.

Posted by: Klikfabriek on December 13, 2003 01:13 PM
Post a comment
Name:


Email Address:


URL:


Comments:


Remember info?



Thank you!

Most Visited Entries
Sketches, Works & Source Code
Lectures
Contact
Backlog
In Love with
Powered by
Movable Type 2.661

© Copyright Mario Klingemann

Syndicate this site:
RSS 1.0 - RSS 2.0

Quasimondo @ flickr
Quasimondo @ LinkedIn
Quasimondo @ Twitter
Quasimondo @ Facebook
Quasimondo @ MySpace
Quasimondo is a Bright
Citizen of the TRansnational Republic
My other blog in german
Impressum


My family name is written Klingemann,
not Klingelmann, Klingeman, Klingaman, Kingemann,
Kindermann, Killingaman, Klingman, Klingmann, Klingonman
Klingemman, Cleangerman, Klingerman or Kleangerman

profile for Quasimondo at Stack Overflow, Q&A for professional and enthusiast programmers