var interval = window.setInterval(animate, 500);
var i = 5;
function animate() {
if (i > 1) {
i--;
console.log(i);
} else {
window.clearInterval(interval);
}
}
animate();
The above javascript has var i = 5; and console logs the numbers 5, 4, 3, 2, and 1. DEMO fiddle
I wanted to put the starting number into the animate() function as an argument though, so I added an argument to animate(), defined the variable i as solely var i;, and put a number into animate():
var interval = window.setInterval(animate, 500);
var i;
function animate(i) {
if (i > 1) {
i--;
console.log(i);
} else {
window.clearInterval(interval);
}
}
animate(10);
DEMO fiddle
However, this second attempt only spits out the number 9, and doesn't spit out 10, 9, 8, 7, etc.
Does anyone know what I'm doing wrong?
You could instead have the function recursively call itself, and use setTimeout with an anonymous function that passes in the current value of i.
function animate(i) {
if (i > 1) {
i -= 1;
console.log(i);
setTimeout(function() {
animate(i);
}, 500);
}
}
animate(10);
This way, you don't need to manage an interval, and the animation will only be controlled by the animate() method. Cleaner IMO.
Working fiddle: http://jsfiddle.net/UNkhK/
If you still want control over the timeout: You could also extend this guy's functionality by making him into an object.
function Animation(delay) {
this.delay = delay || 500;
this.timeout = null;
}
Animation.prototype.animate = function(i) {
if (i > 1) {
i -= 1;
console.log(i);
var self = this;
this.timeout = setTimeout(function() {
self.animate(i);
}, this.delay);
}
}
Animation.prototype.stop = function() {
clearTimeout(this.timeout);
}
var animation = new Animation(500);
animation.animate(10);
// Testing
setTimeout(function() {
animation.stop();
console.log('Animation stopped prematurely!');
}, 2000);
Working fiddle / demo: http://jsfiddle.net/5dZyd/
Function arguments are local variables that shadow global variables. So if you use the same name i for the argument, you can't access the global variable that has that name. You need to use different variables.
var global_i;
function animate(local_i) {
if (local_i !== undefined) { // Will be undefined when called from setInterval
global_i = local_i;
}
if (global_i > 1) {
global_i--;
console.log(global_i);
} else {
window.clearInterval(interval);
}
}
animate(10);
you didnt use the variable i, you created a new one, in short, i inside the function definition - animate(i) creates a new var i for the function, and doesn't use the global one try
var i = 10;
function animate() {
if (i > 1) {
i--;
console.log(i);
}
/*
rest of your code here
*/
animate();
see javascript scoping
also use setTimeout not setInterval see here
fiddle
You may try this (call the function from within the function itself and pass the variable i)
var interval;
function animate(i) {
if (i > 1) {
i--;
console.log(i);
interval = setTimeout(function(){ animate(i) }, 500);
}
}
animate(10);
FIDDLE.
Related
How to call a function 10 times like
for(x=0; x<10; x++) callfunction();
but with 1 sec between each call?
function callNTimes(func, num, delay) {
if (!num) return;
func();
setTimeout(function() { callNTimes(func, num - 1, delay); }, delay);
}
callNTimes(callfunction, 10, 1000);
EDIT: The function basically says: make a call of the passed function, then after a bit, do it again 9 more times.
You can use setInterval for repeated execution with intervals and then clearInterval after 10 invocations:
callfunction();
var callCount = 1;
var repeater = setInterval(function () {
if (callCount < 10) {
callfunction();
callCount += 1;
} else {
clearInterval(repeater);
}
}, 1000);
Added: But if you don't know how long it takes your callfunction to execute and the accurate timings between invocation starting points are not important it seems it's better to use setTimeout for reasons mentioned by Paul S and those described in this article.
Another solution
for(var x=0; x<10; x++) window.setTimeout(callfunction, 1000 * x);
You can try to use setInterval and use a variable to count up to 10. Try this:
var number = 1;
function oneSecond () {
if(number <= 10) {
// execute code here..
number++;
}
};
Now use the setInterval:
setInterval(oneSecond, 1000);
Similar to Amadan's answer but with a different style of closure which means you re-use instead of creating new functions
function call(fn, /* ms */ every, /* int */ times) {
var repeater = function () {
fn();
if (--times) window.setTimeout(repeater, every);
};
repeater(); // start loop
}
// use it
var i = 0;
call(function () {console.log(++i);}, 1e3, 10); // 1e3 is 1 second
// 1 to 10 gets logged over 10 seconds
In this example, if you were to set times to either 0 or Infinity, it would run forever.
I don't know if there's a proper name, but I use a repeater:
function Repeater(callback, delay, count) {
var self = this;
this.timer = setTimeout(function() {self.run();},delay);
this.callback = callback;
this.delay = delay;
this.timesLeft = count;
this.lastCalled = new Date().getTime();
}
Repeater.prototype.run = function() {
var self = this;
this.timesLeft--;
this.callback();
this.lastCalled = new Date().getTime();
if( this.timesLeft > 0) {
this.timer = setTimeout(function() {self.run();},this.delay);
}
}
Repeater.prototype.changeDelay = function(newdelay) {
var self = this;
clearTimeout(this.timer);
this.timer = setTimeout(function() {self.run();},
newdelay-new Date().getTime()+lastcalled);
this.delay = newdelay;
}
Repeater.prototype.changeCount = function(newcount) {
var self = this;
if( this.timesLeft == 0) {
this.timer = setTimeout(function() {self.run();},this.delay);
}
this.timesLeft = newcount;
if( this.timesLeft == 0) clearTimeout(this.timer);
}
You can then use it like this:
new Repeater(callfunction, 1000, 10); // 1 second delay, 10 times
const functionCounterTimer = (callCount) => {
if (callCount < 10) {
setTimeout(() => {
++callCount
console.log("Function Call ", callCount);
functionCounterTimer(callCount);
}, 1000);
}
}
functionCounterTimer(0);
The above was my approach to a similar question.
setInterval(function(){},1000);
Calls the function for every second...
You can also use setTimeout for your thing to work.
I did some digging around on SO and could not find exactly what I am trying to achieve.
In simplistic terms I have a function like
function(){
for(i=0;i<10;i++){
setInterval(function(){ alert(i);), 1000)
}
}
What I would expect is 10 setIntervals that would alert 1 to 10 every 1 second, what happens is it would alert 10 always since 'i' is 10 at the end of for loop. How do I pass 'i' to setInterval anonymous function so that I can preserve the value of i in setInterval?
Above was a simplistic version of my actual problem. I am actually trying to do this
var timers = [];
function(obj){
//Clear any intervals
for(i=0;i<timer.length;i++){
clearInterval(timers[i]);
}
// Empty timers Array
timers = [];
for(i in obj){
//My object from the dom. This guy is what I am trying to preserve
my_obj = document.getElementById(i);
if(obj[i] === "Something"){
timers.push(setInterval(function(){
my_obj.replace_class(["Something", "Otherthing"],"Something");
}, 1000)
}
}
}
my_obj in the above code always refers to id = last 'i' in obj.
Do I make sense?
This should do the trick ;)
for(i = 1; i < 11; i++){
(function(local_i){
setInterval(function(){ console.log(local_i); }, 1000 * local_i)
})(i);
}
You must capture the variable in a closure. In your case this is
function capture(x) {
setInterval(function () {
console.log(x);
}, 1000);
}
for (var i = 0; i < 10; i++) {
capture(i);
}
or
function capture(my_obj) {
var id = setInterval(function() {
my_obj.replace_class(["Something", "Otherthing"],"Something");
}, 1000);
return id;
}
for (i in obj) {
//My object from the dom. This guy is what I am trying to preserve
my_obj = document.getElementById(i);
if (obj[i] === "Something") {
timers.push(capture(my_obj));
}
}
Well I did not know what exactly would be a good title for this because it is a most peculiar situation or I'm abnormally dumb.
Here's what im trying to do.
Create a simple <meter> tag which is new in HTML5. The main issue is with my javascript. Im trying to increment the value of the meter tag gradually in my javascript. But somehow it doesn't work the way i want.
JavaScript.
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function () {
console.log(i);
a.value = i;
}, 250);
}
I'm trying to increase the value of the meter gradually every 250 ms.This doesn't happen. Instead the meter jumps straight to 10.
What interested me was the value of i that i got in the console. I got instances of 10, instead of 1,2,3...10.
Why does this happen?
FIDDLE
It's a JavaScript closures' classic. Here i is an actual reference to the variable, not its copy. After you've iterated through the loop it has the value of 10, that's why all log invocations write 10 to log.
This should work better:
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function (i) {
return function() {
console.log(i);
a.value = i;
};
}(i), 250 * i);
}
Here the most inner i is the setTimeout's callback argument, not the variable which you've declared in the loop body.
You should read more about closures in JavaScript. When a variable gets closed over, it's the same exact variable, not a copy. Since setTimeout is asynchronous, the whole loop finishes before any of the functions run, therefore the i variable will be 10 everywhere.
DEMO
function incMtrAsync(max, delay, el) {
if (el.value++ < max) {
setTimeout(incMtrAsync.bind(null, max, delay, el), delay);
}
}
incMtrAsync(10, 250, document.getElementById("mtr1"));
The above implementation implements the loop using a recursive approach. Everytime inMtrAsync is called, it checks if the value of the meter reached the max value, and if not, registers another timeout with a callback to itself.
If you want to delay the initial increment as well, just wrap the first call in another timeout.
setTimeout(incMtrAsync.bind(null, 10, 250, document.getElementById("mtr1")), 250);
Nobody used setInterval, so here's my solution ( http://jsfiddle.net/Qh6gb/4/) :
var a = document.getElementById("mtr1");
var i = 0;
var interval = setInterval(function () {
console.log(i);
a.value = ++i;
if (i == 10) {
clearInterval(interval);
}
}, 250);
The problem you describe happens before the asyncronous call to setTimeout in your original version sees a value of 10 for i because that is its value at the moment the callback is executed.
So, this is a problem with the scope of the closure, to make it work you should make it like this:
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
(function (i, a) {
setTimeout(function () {
console.log(i);
a.value = i;
}, 250);
})(i, a);
}
also, since a is always the same, this should be better:
var a = document.getElementById("mtr1");
for (var i = 0; i <= 10; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
a.value = i;
}, 250);
})(i);
}
If then you want to see the counter "ticking up", this will make it visible:
var a = document.getElementById("mtr1");
for (var i = 0; i <= 10; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
a.value = i;
}, 1000 * i);
})(i);
}
See http://jsfiddle.net/LDt4d/
It happens because you called setTimeout, which is "asynchronous". So setTimeout is called 10times but after whole loop is done then it is executed. Therefore, i = 10 in each call...
http://jsfiddle.net/Qh6gb/9/
there is the solution:
var i = 1,
meter = document.getElementById("mtr1");
function increase() {
meter.value = i++;
console.log(i);
if(i<=10) {
setTimeout(increase, 250);
}
}
setTimeout(increase, 250);
you can use timeout jquery plugin:. It is easier
However you should calculate your timeout ,
For you ,timeout=250*max=250*10=2500
So
$('meter').timeout(2500);
Demo
Run for loop inside the function instead of declaring a closure in every step of the loop.
JSFIDDLE: http://jsfiddle.net/Qh6gb/3/
var a = document.getElementById("mtr1");
setTimeout(function () {
for (var i = 0; i < 10; i++) {
console.log(i);
a.value = i;
}
}, 250);
I hope I understand right. Please try and tell me if you got solution.
var count = 0;
function increment(){
document.getElementById("meter").value = count;
count++;
if(count ==10)
count=0;
}
setInterval(increment, 250);
Please check with jsFiddle
You're creating multiple functions that are all being set off at the same time.
Multiply the timer by i for correct delay.
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function () {
console.log(i);
a.value = i;
}, 250 * i);
}
I am trying to create a page which needs to preform lots of loops. Using a while/for loops cause the page to hang until the loop completes and it is possible in this case that the loop could be running for hours. I have also tried using setTimeout, but that hits a recursion limit. How do I prevent the page from reaching a recursion limit?
var looper = {
characters: 'abcdefghijklmnopqrstuvwxyz',
current: [0],
target: '',
max: 25,
setHash: function(hash) {
this.target = hash;
this.max = this.characters.length;
},
getString: function() {
string = '';
for (letter in this.current) {
string += this.characters[this.current[letter]];
}
return string;
},
hash: function() {
return Sha1.hash(this.getString());
},
increment: function() {
this.current[0] += 1;
if (this.current[0] > this.max) {
if (this.current.length == 1) {
this.current = [0, 0];
} else {
this.current[1] += 1;
this.current[0] = 0;
}
}
if (this.current[1] > this.max) {
if (this.current.length == 2) {
this.current[2] == 0;
} else {
this.current[3] += 1;
this.current[2] = 0;
}
}
},
loop: function() {
if (this.hash() == this.target) {
alert(this.getString());
} else {
this.increment();
setTimeout(this.loop(), 1);
}
}
}
setInterval is the usual way, but you could also try web workers, which would be a more straightforward refactoring of your code than setInterval but would only work on HTML5 browsers.
http://dev.w3.org/html5/workers/
Your setTimeout is not doing what you think it's doing. Here's what it's doing:
It encounters this statement:
setTimeout(this.loop(), 1);
It evaluates the first argument to setTimeout, this.loop(). It calls loop right there; it does not wait for a millisecond as you likely expected.
It calls setTimeout like this:
setTimeout(undefined, 1);
In theory, anyway. In reality, the second step never completes; it recurses indefinitely. What you need to do is pass a reference to the function rather than the returned value of the function:
setTimeout(this.loop, 1);
However, then this will be window on the next loop, not looper. Bind it, instead:
setTimeout(this.loop.bind(this), 1);
setInterval might work. It calls a function every certain amount of milliseconds.
For Example
myInterval = setInterval(myFunction,5000);
That will call your function (myFunction) every 5 seconds.
why not have a loop checker using setInterval?
var loopWorking = false;
function looper(){
loopWorking = true;
//Do stuff
loopWorking = false;
}
function checkLooper()
{
if(loopWorking == false)
looper();
}
setInterval(checkLooper, 100); //every 100ms or lower. Can reduce down to 1ms
If you want to avoid recursion then don't call this.loop() from inside of this.loop(). Instead use window.setInterval() to call the loop repeatedly.
I had to hand-code continuation passing style in google-code prettify.
Basically I turned
for (var i = 0, n = arr.length; i < n; ++i) {
processItem(i);
}
done();
into
var i = 0, n = arr.length;
function work() {
var t0 = +new Date;
while (i < n) {
processItem(i);
++i;
if (new Date - t0 > 100) {
setTimeout(work, 250);
return;
}
}
done();
}
work();
which doesn't hit any recursion limit since there are no recursive function calls.
I have a ajax javascript method that pulls data from a page etc.
I want this process to run on a timed interval, say every minute.
But I don't want it to loop forever, so max out at 3 times.
What is the best way to implement this?
Like this:
var runCount = 0;
function timerMethod() {
runCount++;
if(runCount > 3) clearInterval(timerId);
//...
}
var timerId = setInterval(timerMethod, 60000); //60,000 milliseconds
A closure-based solution, using setInterval() and clearInterval():
// define a generic repeater
var repeater = function(func, times, interval) {
var ID = window.setInterval( function(times) {
return function() {
if (--times <= 0) window.clearInterval(ID);
func();
}
}(times), interval);
};
// call the repeater with a function as the argument
repeater(function() {
alert("stuff happens!");
}, 3, 60000);
EDIT: Another way of expressing the same, using setTimeout() instead:
var repeater = function(func, times, interval) {
window.setTimeout( function(times) {
return function() {
if (--times > 0) window.setTimeout(arguments.callee, interval);
func();
}
}(times), interval);
};
repeater(function() {
alert("stuff happens!");
}, 3, 2000);
Maybe the latter is a bit easier to understand.
In the setTimeout() version you can ensure that the next iteration happens only after the previous one has finished running. You'd simply move the func() line above the setTimeout() line.
A reusable approach
function setMaxExeuctionInterval( callback, delay, maxExecutions )
{
var intervalCallback = function()
{
var self = intervalCallback;
if ( 'undefined' == typeof self.executedIntervals )
{
self.executedIntervals = 1;
}
if ( self.executedIntervals == maxExecutions )
{
clearInterval( self.interval )
}
self.executedIntervals += 1;
callback();
};
intervalCallback.interval = setInterval( intervalCallback, delay );
}
// console.log requires Firebug
setMaxExeuctionInterval( function(){ console.log( 'hi' );}, 700, 3 );
setMaxExeuctionInterval( function(){ console.log( 'bye' );}, 200, 8 );
This anonymous function (it doesn't introduce any new globals) will do what you need. All you have to do is replace yourFunction with your function.
(function(fn, interval, maxIterations) {
var iterations = 0,
id = setInterval(function() {
if (++iterations > maxIterations)
return clearInterval(id);
fn();
}, interval);
})(yourFunction, 60000, 3);
you can do with setInterval
var count = 0;
var interval = setInterval(yourFunction(), 1000);
function yourFunction (){
clearInterval(interval);
if(count < 3){
count ++;
interval = setInterval(yourFunction(), 1000);
}
// your code
}
To extend Tomalak function:
If you want to know how many cycles are left:
var repeater = function(func, times, interval) {
window.setTimeout( function(times) {
return function() {
if (--times > 0) window.setTimeout(arguments.callee, interval);
func(times);
}
}(times), interval);
}
and use:
repeater(function(left){
//... (do you stuff here) ...
if(left == 0) {
alert("I'm done");
}
}, 3, 60000);
Use setInterval, be sure to get a reference.
var X=setInterval(....);
Also, have a global counter
var c=0;
Inside the function called by the setIntervale do:
c++;
if(c>3) window.clearInterval(X);
You can use setInterval() and then inside the called function keep a count of how many times you've run the function and then clearInterval().
Or you can use setTimeout() and then inside the called function call setTimeout() again until you've done it 3 times.
var testTimeInt = 3;
function testTime(){
testTimeInt--;
if(testTimeInt>0)
setTimeOut("testTime()", 1000);
}
setTimeOut("testTime()", 1000);