2

Im wondering how to properly "Clear" a object instance. With the code below, the internal setInterval() will continue to run even after the instance is "cleared" by the parent.

// simple Class
var aClass = function(){
    return {
        init: function(){
            console.log("aClass init()")
            setInterval( this.tick, 1000 );
            // note: we're not storing the ref
        },
        tick: function(){
            console.log("aClass tick");
        }
    }
}

// instantiate the class
var inst = new aClass();
inst.init();


// try to forget the instance
function test(){
    console.log("test() 1 inst:", inst);

    inst = null;

    console.log("test() 2 inst:", inst);
}

// run for a while, then call test()
setTimeout( test, 4000 );

Output:

aClass init()
aClass tick
aClass tick
aClass tick
test() 1 inst: {.....}
test() 2 inst: null
aClass tick
aClass tick ...

Problem is that the "aClass tick" message continues to print after the test().

Ideas?

braX
  • 11,506
  • 5
  • 20
  • 33
jorgenskogmo
  • 35
  • 1
  • 5
  • 3
    `setInterval` and its handler has nothing to do with your object. – VisioN Jan 20 '13 at 00:32
  • 3
    @VisioN - the OP's point is that if a reference to the object is maintained in a closure, the object isn't ever really "deleted". – nrabinowitz Jan 20 '13 at 00:34
  • The object is deleted, inst is null in the second console log. The function tick is copied when used as a parameter to setInterval. – HMR Jan 20 '13 at 03:07
  • Possible duplicate of [Stop setInterval call in JavaScript](http://stackoverflow.com/questions/109086/stop-setinterval-call-in-javascript) – Floris Dec 25 '15 at 22:52

4 Answers4

3

Your instance is being kept in memory because the function you passed to setInterval is being kept in memory and has a reference to it. That function is referenced by the browser's list of active interval timers.

You'll need to remember the interval handle:

this.intervalHandle = setInterval( this.tick, 1000 );

...then later when you're dropping your reference to inst, you'll want to tell it that:

inst.cleanup();
inst = null;

...and in inst.cleanup:

clearInterval(this.intervalHandle);

That way, the browser will remove its reference to the function you passed to setInterval, which means that function will become eligible for garbage collection (based on your code there are no other references to it). And that means the reference it has to your instance is released, and so if no other outstanding references to that instance exist, it's eligible for garbage collection.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks for super explanation. This is exactly what I feared. Is there really no way to "force-delete" it? – jorgenskogmo Jan 20 '13 at 20:52
  • 1
    @jorgenskogmo: No, the nature of garbage-collected environments is that the only way to "delete" something is to ensure there are no outstanding references to it and let the GC do its thing. In this case, that's pretty easy, though, as described. If you *could* force it, that would just introduce new problems (errors caused by things referencing something that you "forced" out of memory). – T.J. Crowder Jan 20 '13 at 22:04
2

You should use clearInterval() rather than try to delete the reference. This has been answered before - see Stop setInterval call in JavaScript

Community
  • 1
  • 1
Floris
  • 45,857
  • 6
  • 70
  • 122
0

That's because the browser itself keeps track of all the functions scheduled with setInterval and setTimeout. (Otherwise you'd have to store the function yourself somewhere, which in most cases would be pretty annoying.) And your function has a reference to a method, so that method stays alive. But I suspect the rest of the object would have been thrown away, though that's a bit difficult to prove.

If you ever plan to unschedule such a function, you need to do so explicitly:

this.interval = setInterval(function, 4000);

// and then later, in some `destroy()` method
clearInterval(this.interval);

And, by the way, you should very rarely need to return a big hash like that from a constructor! Work with the prototype instead:

var SomeClass = function() {
    // ...
};

SomeClass.prototype.method = function() {
    console.log('hello from', this);
};
Eevee
  • 47,412
  • 11
  • 95
  • 127
  • Regarding the "store a ref to the setInterval()" - Yes. Thanks. About the prototype vs constructor > return {}, this seems to be about coding "style" or habit - or is there really a reason to one instead of the other? – jorgenskogmo Jan 20 '13 at 20:57
  • most habits exist for a reason: in this case, you're creating a new copy of the _entire class_ every time you create an object. – Eevee Jan 20 '13 at 21:44
0

My guess is that your instance of aClass is gone since there is no way to access any of it's properties but in init the tick function is copied when used as a parameter to setinterval.

var tickfunction=null;
var aClass = function(){
    return {
        init: function(){
            console.log("aClass init()")
            tickfunction = this.tick;
        },
        tick: function(){
            console.log("aClass tick");
        }
    }
}

// instantiate the class
var inst = new aClass();
inst.init();

// try to forget the instance
console.log("test() 1 inst:", inst);
inst = null;
console.log("test() 2 inst:", inst);// its null isn't it?
console.log("the tickfunction:",tickfunction);

To illustrate that the function is copied:

function toInterval(){
    console.log("orig");
}
setInterval(toInterval,1000);//prints orig every second
toInterval=function(){
    console.log("changed it");
}
toInterval();//prints changed it
HMR
  • 37,593
  • 24
  • 91
  • 160