Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to kick-ass pass scope through "setInterval"

I'm currently wondering if there is a better solution than passing this scope to the lambda-function via the parameter 'e' and then passing it to 'funkyFunction' using call()-method

setInterval(function(e){e.funkyFunction.call(e)}, speed, this)

(Minor question aside: I'd been reading something about memory-leaks in javascript. How does the lambda-function affect my memory? Is it better to define it first like var i = function(e)... and then passing it as a parameter to setInterval?)

like image 343
PenthousePauper Avatar asked Aug 15 '10 18:08

PenthousePauper


4 Answers

My situation may have been a bit different, but here's what I did:

var self = this;
setInterval(function() { self.func() }, 50);

My scenario was that my code was inside a class method and I needed to keep correct scope as I didn't want the 'this' binding to resolve to the current window.

eg. I wanted to run MyClass.animate from MyClass.init using setInterval so I put this scope-keep code into MyClass.init

like image 50
Jacksonkr Avatar answered Oct 16 '22 05:10

Jacksonkr


You can use native bind function.

function Loop() {
    this.name = 'some name for test';
    setInterval( (function(){//wrap the function as object
        //after bind, "this" is loop refference
        console.log(this);
    }).bind(this), 1000 );// bind the object to this (this is Loop refference)
}

var loop = new Loop();

paste this example in the console to see the result

like image 43
CORSAIR Avatar answered Oct 16 '22 06:10

CORSAIR


What's wrong with simply relying on the outer-scope defined variable?

(function() { 

    var x = {};
    setInterval(function() {
       funkyFunction.call(x)
    }, speed);

})();
like image 28
meder omuraliev Avatar answered Oct 16 '22 07:10

meder omuraliev


I had the same question, but there seems to be no built in solution, so here is a quick workaround I punched together:

function setScopedInterval(func, millis, scope) {
    return setInterval(function () {
        func.apply(scope);
    }, millis);
}

usage:

function MyClass() {
    this.timer = null;
    this.myFunc = function() { console.log('do some stuff'); };
    this.run = function() {
        this.timer = setScopedInterval(function () { this.myFunc(); }, 1000, this);
    };
    this.stop = function() { clearInterval(this.timer); };
}
var instance = new MyClass();
instance.run(); // will log to console every second
// until this line is called
instance.stop();

This only covers the use-case where you pass an actual function, not a string of code to be executed.

As for your question about memory leaks when using this functionality: it is not so much the problem with using setInterval as it is with anonymous functions in itself. If you use a reference to an object inside a lambda, this reference will keep the referenced object in memory for as long as the anonymous function exists. I think the function is destroyed with a call to clearInterval.

I don't think there is any benefit from assigning the function to a variable first, on the contrary, it will create another variable containing a reference that will not be garbage collected as long as the anon func exists...

like image 41
NDM Avatar answered Oct 16 '22 05:10

NDM