Calling setTimeout in a loop not working as expect

2019-06-24 11:05发布

The following JavaScript ought to (in my mind) play a sequence of notes 0.5 sec apart. But it plays them all as a single simultaneous chord. Any idea how to fix it?

function playRecording() {
    if (notes.length > 0) {
        for (var i = 0; i < notes.length; i++) {
            var timeToStartNote = 500 * i;
            setTimeout(playNote(i), timeToStartNote);
        }
    }
}

function playNote(i) {
    var noteNumber = notes[i];
    var note = new Audio("/notes/note_" + noteNumber + ".mp3");
    note.play();
}

3条回答
甜甜的少女心
2楼-- · 2019-06-24 11:36

Thanks folks, and here is the complete solution to my question:

function playRecording() {
    if (notes.length > 0) {
        for (var i = 0; i < notes.length; i++) {
            playNote(i);
        }
    }
}

function playNote(i) {
    setTimeout(function () {
        var noteNumber = notes[i];
        var note = new Audio("/notes/note_" + noteNumber + ".mp3");
        note.play();
    }, 500 * i);
}
查看更多
唯我独甜
3楼-- · 2019-06-24 11:46

Very simple actually, in the for loop you call the function playNote(i) which plays the note i instantaneously (and therefore play many notes instantly like a chord since it is in a really fast running for loop). Instead you should try code this which lets the timeout actually play the note. The setTimeout function expects the function as an argument instead you called the function.

(function(j){setTimeout(function(){playNote(j);},j*500);}(i));
查看更多
女痞
4楼-- · 2019-06-24 11:47

JavaScript closures, wrap this in a self-executing function:

for (var i = 0; i < notes.length; i++) { 
    (function(i) {
       var timeToStartNote = 500 * i;
       setTimeout(function() {
           playNote(i)
       }, timeToStartNote);
    })(i)
}
查看更多
登录 后发表回答