Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript setTimeout in foreach: need help creating a closure

I have this function

notes.forEach(function(note) {          
    setTimeout(function() {
        playNote(note);
    }, 1000);
});

This doesn't work. It plays all the notes at the same time, instead of playing them sequentially with a 1 second gap in between. It looks like I need to have a closure here to make this work. Could someone help me fix this function so it would play the note with the delay between each note?

like image 815
Prabhu Avatar asked Feb 20 '14 10:02

Prabhu


People also ask

Does setTimeout work inside forEach?

The setTimeout() method sets a timer which executes a function or specified piece of code once the timer expires. names. forEach((name) => { setTimeout(() => { display(name); }, 1000); }); But all that happens here is that nothing is displayed for 1000 milliseconds (1 second), then we see the last name again!

Is setTimeout a closure?

It's important to understand that closures are created when functions are created, not when they are invoked. And because a closure was created when this setTimeout function was created, this enables the setTimeout function to access the i variable at whatever time the setTimeout function will run.

Is forEach a closure?

forEach() creates closures.

Does setTimeout work in a for loop?

setTimeout function in JavaScript usually takes a callback function as an argument. A callback function is a function that is executed after another function finishes running. In this case, it will run after for loop finishes.


2 Answers

There are two ways to do this:

1) Have a function that grabs one note every second until there are no more notes:

var interval = setInterval(function() {
  playNote(notes.shift()); // changes the notes array!
  if (!notes.length) clearInterval(interval);
}, 1000);

2) Start all the timers at the same time with different delays:

notes.forEach(function(note, index) {
  setTimeout(playNote.bind(null, note), index*1000);
});
like image 119
Tibos Avatar answered Nov 02 '22 19:11

Tibos


because all timeouts are set at the same time...

Do something like this:

playAllNotes(0);
function playAllNotes(index) {
    if(notes.length > index) {
        setTimeout(function() {
            playNote(notes[index]);
            playAllNotes(++index);
        }, 1000);
    }
}
like image 20
Cracker0dks Avatar answered Nov 02 '22 18:11

Cracker0dks