I'm trying to be a good citizen and keep as much out of the global scope as possible. Is there a way to access setTimeout variables that are not in the global scope?
So that, in this example how would someone cancel 'timer'?
myObject.timedAction = (function(){
var timer;
return function(){
// do stuff
// then wait & repeat
timer = setTimeout(myObject.timedAction,1000);
};
})();
I've tried clearTimeout(myObject.timedAction.timer,1000); (without success), and not sure what else to try.
You can't unless you have a reference to timer, which you don't because you're declaring it as a variable in a scope. You can do something like:
myObject.timedAction = (function(){
return function(){
// do stuff
// then wait & repeat
myObject.timedAction.timer = setTimeout(myObject.timedAction,1000);
};
})();
clearTimeout(myObject.timedAction.timer);
Note that the above code will only ever allow ONE timer. If you need references to more than one timer, it needs to be adjusted.
The whole point is that the inner variables are private, and inaccessible to the outside world. SO you have to change your approach a bit:
myObject.timedAction = (function(){
var timer;
var result = function(){
// do stuff
// then wait & repeat
timer = setTimeout(myObject.timedAction,1000);
};
result.cancel = function() {
clearTimeout(timer);
};
return result;
})();
myObject.timedAction(); // start it
myObject.timedAction.cancel() // end it
So now the timer is only ever accessed from inside the closure. And yes, you can add methods to a function, because JS is awesome.
Put the timer handle in a property in your object:
myObject.timedAction = function(){
// do stuff
// then wait & repeat
this.timer = window.setTimeout(function(){ myObject.timedAction(); },1000);
};
Note that you should wrap the call from the timer in a function, so that it's called as a method of your object instead of as a global function, otherwise you won't be able to access your object using this.
Now you can stop the timer using:
window.clearTimeout(myObject.timer);
Related
JavaScript has all amounts of crazy flexibility. I decided to take advantage of it and have a function change itself on the first call. Is this a bad thing to do? It works like this:
(function(){
var nextAfter = function(){};
Something.prototype.next = function(){
//do pre-start actions.
this.next = nextAfter;
};
})();
This function is called inside of a main loop, so it gets called many times, but the instance is only ever "supposed" to be instantiated once.
It is a perfectly reasonable thing to do.
For example, It can be a useful way of implementing state changes in a state machine, but I'm sure that you could find many other uses.
You may also want to look into how to implement the same functionality with closures -- it may be cleaner depending on the use case.
Edit; example of a closure which doesn't change the prototype
Something = (function(){
var next = function() { next = nextAfter; console.log("A"); }
var nextAfter = function() { console.log("B"); }
return {
next: function(){ next(); }
}
})();
The benefit of the closure is that you don't change the global prototype function for that object type, and you can now have multiple independent object where each closure object can keep their own state.
I was reading a post about how to fire a function after a window resize was complete and came across some examples that assigned self executing anonymous functions to variables:
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
$(window).resize(function() {
delay(function(){
alert('Resize...');
//...
}, 500);
});
What is the difference/benefit of making the function operand self executing as opposed to it's traditional use? i.e.
var delay = function() { ...
The main reason for this is namespacing variables. Functions introduce a new variable scope. In the case of the above example, timer is not clobbering the global namespace while still being available to the code that needs it.
Since I apparently need to clarify:
The goal is to have a variable outside the function:
var timer;
function delay() {
// use timer
}
Because if the variable would be inside the function, it would be reinitialized every time. We want a persistent value outside the function though.
In the above code timer is a global variable though. We don't want that. To avoid that, we close the variable up in a new scope so it's accessible to the delay function, but not globally:
var delay = (function () {
var timer;
return function () {
// use timer
};
})();
delay is now a function just as before which can use timer outside itself, yet timer is not in the global scope.
I repeat execution of function on every second like
setInterval(function(){ /* some code */},1000};
What to change so function would be executed first time immediately and then repeats on every 1 second, any parameter I missed ?
You can use a self-executing function:
(function Fos () {
//do your stuff here
setTimeout(Fos, 1000);
})();
This function will invoke itself, and then set a timeout to run itself again in a second.
EDIT: Just one more note. In my example I used a named function expression (I used the name "Fos"), which allows us to reference the function itself inside the function. Some other examples use arguments.callee, which does not even work in ECMAScript 5 Strict mode, and generally not a recommended practice nowadays. You can read more about it in the SO question Why was the arguments.callee.caller property deprecated in JavaScript?
You might want to declare the function, run it and after that set the interval:
function something() { /* ... */ } // declare function
something(); // run it now immediately (once)
setInterval(something, 1000); // set an interval to run each second from now on
nope. the best you can do is:
var worker = function() { /* code */ }
worker();
setInterval(worker, 1000)
You could use a slightly different pattern like this:
(function() {
/*code*/
setTimeout(arguments.callee, 1000);
})()
Note that arguments.callee isn't allowed in strict mode, so then you could do something like:
var worker = function() {
/*code*/
setTimeout(worker, 1000);
}
worker();
The latter two code examples will create a function that will call itself 1000 milliseconds after executing. See this link for more details on the differences (advantages/disadvantages) between using setInterval() and setTimeout() chaining.
An additional solution to the ones already suggested is to return the anonymous function in its declaration, and calling the function immediately after it has been declared.
This way you don't have to use an additional variable and you can still use the interval ID returned by setInterval, which means that you can abort it using clearInterval later.
Eg. http://jsfiddle.net/mqchen/NRQBK/
setInterval((function() {
document.write("Hello "); // stuff your function should do
return arguments.callee;
})(), 1000);
I've made this code:
window.setInterval(function(){ var a = doStuff(); var b = a + 5; }, 60000)
The actual contents of the anonymous function is of course just for this small example as it doesn't matter. What really happens is a bunch of variables get created in the scope of the function itself, because I don't need/want to pollute the global space.
But as you all know, the doStuff() function won't be called until 60 seconds in the page. I would also like to call the function right now, as soon as the page is loaded, and from then on every 60 seconds too.
Is it somehow possible to call the function without copy/pasting the inside code to right after the setInterval() line? As I said, I don't want to pollute the global space with useless variables that aren't needed outside the function.
You can put your callback function in a variable, and wrap up everything in a self-invoking anonymous function:
(function () {
var callback = function() {
var a = doStuff();
var b = a + 5;
};
callback();
window.setInterval(callback, 60000);
})();
No pollution.
This is possible without creating global variables as well:
setInterval((function fn() {
console.log('foo'); // Your code goes here
return fn;
})(), 5000);
Actually, this way, you don’t create any variables at all.
However, in Internet Explorer, the fn function will become accessible from the surrounding scope (due to a bug). If you don’t want that to happen, simply wrap everything in a self-invoking anonymous function:
(function() {
setInterval((function fn() {
console.log('foo'); // Your code goes here
return fn;
})(), 5000);
})();
Credit to Paul Irish for sharing this trick.
Edit: Answer updated with some more information, thanks to bobince.
yet another solution:
(function() {
var a = doStuff();
var b = a + 5;
window.setTimeout(arguments.callee, 60000);
})();
This uses timeout instead of interval so that it can run the first time and then run it's self again after a timeout.
I'm currently having an issue where I have a javascript object that is trying to use setInterval to call a private function inside of itself. However, it can't find the object when I try to call it. I have a feeling that it's because window.setInterval is trying to call into the object from outside but doesn't have a reference to the object. FWIW - I can't get it to work with the function being public either.
The basic requirement is that I may need to have multiple instances of this object to track multiple uploads that are occurring at once. If you have a better design than the current one or can get the current one working then I'm all ears.
The following code is meant to continuously ping a web service to get the status of my file upload:
var FileUploader = function(uploadKey) {
var intervalId;
var UpdateProgress = function() {
$.get('someWebService', {},
function(json) {
alert('success');
});
};
return {
BeginTrackProgress: function() {
intervalId = window.setInterval('UpdateProgress()', 1500);
},
EndTrackProgress: function() {
clearInterval(intervalId);
}
};
};
This is how it is being called:
var fileUploader = new FileUploader('myFileKey');
fileUploader.BeginTrackProgress();
Use this
intervalId = window.setInterval(UpdateProgress, 1500);
setInterval with a literal argument will eval this in the global scope where UpdateProgress is not accessible.
Because it is an eval expression, it does not have access to the scope that setInterval is created in. Try:
intervalId = window.setInterval(UpdateProgress, 1500)
It is generally good practice to avoid eval style expressions wherever possible. For instance, if you wanted to call several functions from the same timer, you would use an anonymous function instead of a string.
window.setInterval(function () {
function1();
function2();
}, 1500)
See also
Why is using javascript eval() a bad idea?
Anonymous function - Wikipedia
+1 to Andy E's head (I can't upvote yet, doh!)
Another gotcha that could get you is if you use this from within the called function.
Then doing exactly what Andy has with this addition should get you by.
var that = this;
window.setInterval(function() {
function1.apply(that);
function2.apply(that);
}, 1500);