IntervalManager


Early on in developing Central apps, I found that I needed something to manage all my Intervals in an application. It was important to have a central place that I could identify, create, and clear intervals, so I developed a singleton manager (IntervalManager) to handle this. In addition, I overloaded the setInterval method, so that one could create delayed calls like setTimeout in javascript, or create an interval that ran N number of times. I managed this by adding a prefixed param N to the setInterval method, which if used tells the interval to run N times, and if not defaults to normal setInterval behavior. Below is the class with usage definitions.

/**
******************************************

@class (SINGLETON): IntervalManager Class
@author: Kenny Bunch

PUBLIC METHODS
setInterval
clearInterval
clearAllIntervals

@usage:
// setting intervals
var id1:Number = IntervalManager.setInterval(2, myFunction, 100, "myArg");
var id2:Number = IntervalManager.setInterval(2, _root, "myFunction", 100, "myArg");
var id3:Number = IntervalManager.setInterval(myFunction, 100, "myArg");
var id4:Number = IntervalManager.setInterval(_root, "myFunction", 100, "myArg");

// clearing intervals
IntervalManager.clearInterval(id1);
IntervalManager.clearAllIntervals();

******************************************
*/

class com.kennybunch.utils.IntervalManager {

        private static var  __intervals:Object = {};

        /**
        @constructor (PRIVATE): IntervalManager
        @comments : can not be instantiated
        */
        private function IntervalManager(Void){}

        /**
        @method (PRIVATE STATIC): createInterval
        @returns : Integer
        */
        private static function createInterval():Number{

                var id:Number = _global.setInterval.apply(_global.setInterval, arguments);

                __intervals[id] = id;

                return id;
        }

        /**
        @method (PUBLIC STATIC): setInterval
        @returns : Integer
        */
        public static function setInterval(iCt, a, b, c, args):Number{

                var func:Function;
                var args:Array;
                var id;

                // for a basic function call:
                if (typeof iCt == "number"){

                        if (typeof arguments[1] == "function"){
                                args = arguments.slice(3);
                                func = function(){
                                        a.apply(null, args);
                                        iCt--;
                                        if (iCt == 0){
                                                clearInterval(id);
                                        }
                                }
                                id = createInterval(func, b, args);
                                // for an object method call:
                        } else{
                                args = arguments.slice(4);
                                func = function(){
                                        a[b].apply(a, args);
                                        iCt--;

                                        if (iCt == 0){
                                                clearInterval(id);
                                        }
                                }

                                id =  createInterval(func, c, args);
                        }
                } else {
                        id = createInterval.apply(IntervalManager, arguments);
                }

                return id;
        }

        /**
        @method (PUBLIC STATIC): clearInterval
        @param (Integer): iId
        @return: Void
        */
        public static function clearInterval(iId:Number):Void{

                _global.clearInterval(iId);
                delete(__intervals[iId]);
        }

        /**
        @method (PUBLIC STATIC): clearAllIntervals
        @return: Void
        */
        public static function clearAllIntervals(Void):Void{

                var each;

                for (each in __intervals){
                        clearInterval(each);
                }
        }
}
  1. #1 by mason on December 3, 2004 - 8:32 am

    Kenny this thing rocks. Thanks for posting.

  2. #2 by riccardo caroli on December 3, 2004 - 11:36 am

    great code, very useful

  3. #3 by casey corcoran on December 3, 2004 - 1:29 pm

    Nice code Kenny, I wrote a similar implementation in AS1. Mine had a nice feature where you could pass an object reference to clearInterval that would stop all intervals running on the given mc, object, etc.

    One thing I noticed and thought I would mention is to watch out for the activation object, you’re opening the door to memory problems.

  4. #4 by dante on December 9, 2004 - 3:21 pm

    wow. absolutly great! thank you for coding it.

  5. #5 by Kenny Bunch on December 23, 2004 - 8:11 am

    Casey,

    Can you explain where there would be memory waste? The activation object is persistant for the life of the function literal. The function literal is only persistent for the life of the interval call. Once clearInterval is called a request to clean the function literal occurs, since the activation object is a child to that scope it is cleaned first and then the reference to the literal is removed. Am I missing something?

  6. #6 by Daniel on January 10, 2005 - 10:42 am

    Thanks for the really helpful code Kenny. Can I ask request that you comment your method arguments and such a little more thoroughly for the slower ones of us? Obviously the code is streamlined but for demonstration purposes it would be really helpful to read more about your thinking at each step (through code comments).

    Thanks again!

  7. #7 by Zeke Danglemeyer on February 20, 2005 - 10:29 am

    One thing I noticed and thought I would mention is to watch out for the activation object, you’re opening the door to memory problems.

    I don’t really see the memory leak here: when the interval is cleared, the property of __intervals is deleted, so theoretically there shouldn’t be any problem.

    Can I ask request that you comment your method arguments and such a little more thoroughly for the slower ones of us?

    I have two more specific requests/examples to add to this.

    The first is that the comment “@returns: Integer” for setInterval would be helped by further detailing what the integer holds, specifically the index/property of __intervals that corresponds to the newly created interval.

    The second comment is mostly agreement with Daniel that since you have done an impressive job of overloading the function the arguments are a bit confusing and I’m not sure still what combinations of arguments it takes. The user confusion probably is further confounded by the fact that arguments are passed on to the default setInterval, which can then pass on arguments to the function the interval: so we have 3 levels of arguments to think about!

    All that said, I am using the manager and I like it … so thanks!

  8. #8 by Aran Rhee on February 22, 2005 - 11:01 pm

    Kenny.

    Great work.

    My 2 cents: it would be really cool/useful to implement the passing of the interval ID into the function being called by your setInterval method.

    This way you can call a clearInterval from within the function without having to manually track the intervalID number.

    I got the idea from : http://www.kirupa.com/developer/actionscript/setinterval2.htm

    (last code example)

    I have implemented the idea into a modified version of your class. I’m not too sure if the way I went about it is the cleanest, but I rewrote the typeof iCt != “number” if/else branch. I also return “args[args.length] = id” instead of returning “id” to make it pass the extra argument.

    Any thoughts of the best way to do this? (without having to add another if/else branch, and messing with arg indexes)

    Cheers.

  9. #9 by Kenny Bunch on February 23, 2005 - 7:54 am

    Aran,

    Interesting implementation. However, it tightly couples the signature of the function to be called to the setInterval implementation. The function being called now has to intrinsically know that setInterval is calling it and to behave accordingly. This is ok for functions that will always be called by setInterval. Though, in a lot of cases you are not always going to call a function via an interval. In these cases, you can not call them correctly without using setInterval, because you are breaking the contract. This limits you in your architecture of your functions. Just something to think about when you architect your projects.

  10. #10 by Aran Rhee on February 23, 2005 - 6:26 pm

    Kenny.

    Thanks for the feedback. For my particualr usage, this was not an issue, but I agree with what you say. I do not consider myself expert when it comes to architecting, but couldn’t you just have some sort of a “wrapper function” which calls calls a generic (non setInterval linked) function (which is used elsewhere in the app).

    function doSomething (txt){
    // do something
    }

    function doSomethingInterval(txt, intervalID){
    doSomething(txt);
    // do something with intervalID if necessary
    }

    setInterval(doSomethingInterval, 100, “abc”);

    Is nesting functions like this considered BAD practice? I guess we are losing the original intended efficiencies by doing this….hmmmm…oh well, we learn….

  11. #11 by Melih on May 14, 2005 - 3:08 pm

    I suppose what he is saying is that you could optimize your class by taking this function definition:

    func = function(){
    a.apply(null, args);
    iCt--;
    if (iCt == 0){
    clearInterval(id);
    }
    }

    and make it a member of the class and assign the variable the class method so you could merge the duplicate codes in these two functions:

    func = function(){
    a.apply(null, args);
    iCt--;
    if (iCt == 0){
    clearInterval(id);
    }
    }

    func = function(){
    a[b].apply(a, args);
    iCt--;
    if (iCt == 0){
    clearInterval(id);
    }
    }

    Since there is no function living within the setInterval method the activation object is removed.

    HE

  12. #12 by Paul Steven on August 14, 2006 - 12:26 am

    Looks like a great class – thanks!

    I would like to use this for a CDROM project I am working on. I am developing 1 of 3 games on the CDROM so I am concerned if I use this class, it may affect other programmers working on other games. I am fairly new to this AS2 coding so would appreciate some reassurance.

    Is there a way I can just use this class in my game and it will not affect the use of the setInterval function for the other programmers developing the other games?

    The structure of the CDROM is such that each game is developed as a separate fla / swf and is loaded into a container movie.

    All the classes for this project are contained in one folder called “classes” therefore am I right in assuming I can just change the following line

    class com.kennybunch.utils.IntervalManager {

    to

    class IntervalManager {

    Many thanks

    Paul

(will not be published)