setTimeoutФункция является асинхронным, и поэтому ваша playPatternфункция будет фактически вернуться до любого из playAudioзадержанных вызовов были сделаны.
Это означает, что removeHighlightон также будет вызван до того, как любой из обратных вызовов тайм-аута будет запущен. Если вы хотите что-то сделать, когда все звуки сыграли, вам понадобится способ управлять вашими асинхронными вызовами функций и запустить обратный вызов, когда все будет завершено.
Мне нравится использовать замечательную асинхронную библиотеку для этого типа вещей, но вы также можете добиться чего-то подобного с обещаниями. С его помощью вы переписываете свою playPatternфункцию следующим образом:
gamePlay
Теперь, когда вы вызываете playPattern, вы можете передать функцию как второй аргумент, который будет вызываться только после завершения всех завершенных setTimeoutвызовов. Вы можете переписать свою gamePlayфункцию следующим образом:
function gamePlay () {
var testArr = [3, 2, 0, 1, 3]
playPattern(testArray, removeHighlight)
}