Javascript setTimeout in foreach: need help creating closure

I have this function

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

This does not work. It plays all notes at once, instead of playing them sequentially with an interval of 1 second. Looks like I need to close here to do this job. Can someone help me fix this feature so that it plays a note with a delay between each note?

+8
javascript closures settimeout
source share
3 answers

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); } } 
+4
source share

There are two ways to do this:

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

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

2) Run all timers simultaneously with different delays:

 notes.forEach(function(note, index) { setTimeout(playNote.bind(null, note), index*1000); }); 
+11
source share

You can use a counter, it's complicated, but worth it if you are working with objects:

 counter = 0; $.each(object, function(index,item){ counter++; var localCounter = counter; setTimeout(function{ console.log('something') }, counter * 1000) // change one to number of milliseconds you need }) 

The first counter is global, so if we are not a var localCounter , we will execute all timeouts at the same time.

0
source share

All Articles