Reputation: 8267
I have this code in ES6:
function loopLettersEvery3Seconds() {
const letters = ['a', 'b', 'c'];
let offset = 0;
letters.forEach((letter, index) => {
setTimeout(() => {
// I do something with the letter, nothing important
}, 3000 + offset);
offset += 3000;
if (index === letters.length - 1) {
loopLettersEvery3Seconds(letters);
}
});
}
This function loop over an array of letters and every 3 second I can do something with every letter. But the thing is that when this loop comes to an end and finish, I can't repeat again the process... The recursive call generates an stack overflow (Uncaught RangeError: Maximum call stack size exceeded) lol
Tell me how to do it! Thanks!!
BR
Upvotes: 1
Views: 1331
Reputation: 26161
I guess a quasi recursive loop is best in this case;
var chars = ["a","b","c"];
function loop(a,i = 0){
console.log(a[i%a.length]);
setTimeout(loop,1000,a,++i);
}
loop(chars);
Upvotes: 0
Reputation: 907
You can do something like this. This is how you can simulate a setInterval via recursion and setTimeouts
var array = ['a', 'b', 'c']
function loopLettersEvery3Seconds(arr, index) {
if (index === arr.length) return;
//Do stuff with array
setTimeout(loopLettersEvery3Seconds, 3000, arr, index+1)
}
loopLettersEvery3Seconds(array, 0)
This way, you don't have to deal with the synchronous nature of loops and instead, do every thing based on the callstack and the web api (is that the right term for timeouts?)
If you want it to loop forever, then do this
var array = ['a', 'b', 'c']
function loopLettersEvery3Seconds(arr, index) {
if (index === arr.length) return loopLettersEvery3Seconds(arr, 0);
setTimeout(loopLettersEvery3Seconds, 3000, arr, index+1)
}
loopLettersEvery3Seconds(array, 0)
Upvotes: 3
Reputation: 16779
You should probably be using setInterval
instead of setTimeout
, which allows you to avoid using an offset
variable. Note that you can use the modulo (%
) operator to make sure that your index "loops" as you increment it:
function loopLettersEvery3Seconds() {
const letters = ['a', 'b', 'c']
let index = 0
setInterval(() => {
console.log(letters[index])
index = (index + 1) % letters.length
}, 3000)
}
loopLettersEvery3Seconds()
Upvotes: 0
Reputation: 664395
forEach
is synchronous. You're doing your recursive call immediately after setting up the last timeout, which obviously will lead to a stack overflow when the function is calling itself without a base case to stop at.
For an forever-running animation, you will want to put the "recursive" call inside the last timeout:
function loopLettersEvery3Seconds() {
['a', 'b', 'c'].forEach((letter, index) => {
setTimeout(() => {
// I do something with the letter, nothing important
if (index === letters.length - 1) {
loopLettersEvery3Seconds(letters);
}
}, 3000 * (index + 1));
});
}
Upvotes: 1