How to kick-ass pass scope through "setInterval"
Solution 1
What's wrong with simply relying on the outer-scope defined variable?
(function() {
var x = {};
setInterval(function() {
funkyFunction.call(x)
}, speed);
})();
Solution 2
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
Solution 3
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
Solution 4
You may also have a look at the YUI
Framework
. It's fine for building applications and easy to learn.
YUI2: YAHOO.lang.later(when, scope, fn, args, periodic);
YUI3: Y.later(when, scope, fn, args, periodic);
UPDATE as example
Using YUI and jQuery (Do not forget enable $.noConflict())
var jQuerySelector = jQuery("div[class^='form-field-']");
jQuerySelector.hide();
jQuery(jQuerySelector[0]).show();
YAHOO.lang.later(5000, jQuery, function(jQuerySelector) {
if((!(this.index)) || (this.index == (jQuerySelector.length))) {
this.index = 0;
}
jQuerySelector.hide();
this(jQuerySelector[this.index++]).show();
}, jQuerySelector, true);
In short
- 1º parameter: 5000 on every 5000 miliseconds, 3º parameter (a function) will be executed
- 2º parameter: jQuery Object in which will be referenced by using this
- 3º parameter: function which will be executed. It receives as parameter either an array or an object passed as 4º parameter
- 5º parameter: true if true, executes continuously at supplied interval until canceled
see http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_later
UPDATE No need for $.noConflict() because YUI does not use $ in any way.
Solution 5
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...
Related videos on Youtube
PenthousePauper
Updated on April 30, 2022Comments
-
PenthousePauper almost 2 years
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?) -
PenthousePauper over 13 yearsMy Problem is, that setInterval is called out of another method of (in your example) 'x'. So I'm basically calling one method out of the other and tried find a tricky solution around closures, conserving a hugh object. Twisted thoughts?
-
Matthew Crumley over 13 years@PenthousePauper: Having a reference to the object in a closure won't cause any memory issues. Passing
this
tosetInterval
would keep the object alive anyway. It's also Firefox-specific, so it won't work everywhere. -
egerardus about 11 years@MatthewCrumley How is it FF specific?
-
Matthew Crumley about 11 years@Geronimo This answer is fine; the FF-specific part is passing a parameter to the callback function, like in the question.
-
7vujy0f0hy over 5 yearsSorry about late comment but I fail to see an advantage of using
setScopedInterval(function () {this.myFunc();}, 1000, this)
oversetInterval(function (x) {x.myFunc();}, 1000, this)
. How aboutvar setScopedInterval = (f, time, scope, ...p) => setInterval((x, p) => x.f(...p), time, scope, p);
instead? Example use:setScopedInterval(this.myFunc, 1000, this, p1, p2, p3)
. -
NDM over 5 yearsin 2013, when this answer was posted, arrow function were not yet implemented in javascript, that's the entire issue of the original question. The difference between anonymous functions and arrow functions is scope inheritance.
-
7vujy0f0hy over 5 yearsI was afraid that my modern notation would distract you from the proper issue... and it did. But forget it, there are novice-level errors in my code:
x.f(...p)
instead ofx[f](...p)
instead off.apply(x, p)
. Likewise:x.myFunc()
instead ofx[myFunc]()
instead ofmyFunc.apply(x)
. Fixing them turns my solutions into your solutions and essentially answers my own question. -
7vujy0f0hy over 5 yearsThere are still other questions: 1. Why
setScopedInterval(function () { this.myFunc(); }, 1000, this);
rather thansetScopedInterval(this.myFunc, 1000, this);
? 2. Why not nativesetInterval(this.myFunc.bind(this), 1000);
instead? Was there nobind
method in 2013? 3. Why not grab this opportunity and allowsetScopedInterval
also pass arguments? Back in 2013, nativesetInterval
didn’t allow passing arguments to the interval function and your function could implement it with minimal code. Like this:func.apply(scope, arguments)
.