Javascript, setTimeout?

Итак, я работаю над музыкальной программой, которая требует, чтобы несколько элементов javascript синхронизировались с другим. Я использую setInterval, который работает очень хорошо изначально, но со временем элементы постепенно перестают синхронизироваться, что с музыкальной программой плохо.

Я читал в Интернете, что setTimeout более точен, и вы можете каким-то образом установить петли setTimeout, однако я не нашел общую версию, которая иллюстрирует, как это возможно. Может ли кто-нибудь просто показать мне базовый пример использования setTimeout для чего-то бесконечно.

Спасибо. В качестве альтернативы, если есть способ добиться более синхронных результатов с помощью setInterval или даже другой функции, пожалуйста, дайте мне знать.

ИЗМЕНИТЬ:

В принципе у меня есть некоторые функции вроде:

//drums
setInterval(function {
//code for the drums playing goes here
},8000);

//chords
setInterval(function {
//code for the chords playing goes here
},1000);

//bass
setInterval(function {
//code for the bass playing goes here
},500);

Сначала он работает очень хорошо, но в течение примерно минуты звуки становятся заметно не синхронизированными, как я читал, с помощью setInterval, я читал, что setTimeout может быть более последовательно точным.

Ответ 1

Вы можете создать цикл setTimeout, используя рекурсию:

function timeout() {
    setTimeout(function () {
        // Do Something Here
        // Then recall the parent function to
        // create a recursive loop.
        timeout();
    }, 1000);
}

Проблема с setInterval() и setTimeout() заключается в том, что нет гарантии, что ваш код будет запущен в указанное время. Используя setTimeout() и вызывая его рекурсивно, вы убедитесь, что все предыдущие операции в таймауте завершены до начала следующей итерации кода.

Ответ 2

Только для дополнения. Если вам нужно передать переменную и повторить ее, вы можете сделать так:

function start(counter){
  if(counter < 10){
    setTimeout(function(){
      counter++;
      console.log(counter);
      start(counter);
    }, 1000);
  }
}
start(0);

Вывод:

1
2
3
...
9
10

Одна строка в секунду.

Ответ 3

Учитывая, что ни одно время не будет очень точным, один из способов использования setTimeout быть немного более точным - рассчитать, как долго была задержка с последней итерации, а затем соответствующим образом настроить следующую итерацию. Например:

var myDelay = 1000;
var thisDelay = 1000;
var start = Date.now();

function startTimer() {    
    setTimeout(function() {
        // your code here...
        // calculate the actual number of ms since last time
        var actual = Date.now() - start;
        // subtract any extra ms from the delay for the next cycle
        thisDelay = myDelay - (actual - myDelay);
        start = Date.now();
        // start the timer again
        startTimer();
    }, thisDelay);
}

Итак, в первый раз, когда он будет ждать (по крайней мере) 1000 мс, когда ваш код будет выполнен, может быть немного поздно, скажем, 1046 мс, поэтому мы вычитаем 46 мс из нашей задержки для следующего цикла и следующего задержка составит всего 954 мс. Это не остановит таймер от увольнения до конца (что следует ожидать), но поможет вам остановить задержки от подпитки. (Примечание: вы можете проверить thisDelay < 0, что означает, что задержка была более чем в два раза выше целевой задержки, и вы пропустили цикл - до вас, как вы хотите справиться с этим делом).

Конечно, это, вероятно, не поможет вам синхронизировать несколько таймеров, и в этом случае вам может понадобиться выяснить, как управлять ими все с помощью одного и того же таймера.

Таким образом, глядя на ваш код, все ваши задержки составляют несколько 500, поэтому вы можете сделать что-то вроде этого:

var myDelay = 500;
var thisDelay = 500;
var start = Date.now();
var beatCount = 0;

function startTimer() {    
    setTimeout(function() {
        beatCount++;
        // your code here...
        //code for the bass playing goes here  

        if (count%2 === 0) {
            //code for the chords playing goes here (every 1000 ms)
        }

        if (count%16) {
            //code for the drums playing goes here (every 8000 ms)
        }

        // calculate the actual number of ms since last time
        var actual = Date.now() - start;
        // subtract any extra ms from the delay for the next cycle
        thisDelay = myDelay - (actual - myDelay);
        start = Date.now();
        // start the timer again
        startTimer();
    }, thisDelay);
}

Ответ 4

Лучший способ справиться с синхронизацией звука - использовать Web Audio Api, у него есть отдельные часы, которые являются точными независимо от того, что происходит в главном потоке. Здесь есть отличное объяснение, примеры и т.д. от Криса Уилсона:

http://www.html5rocks.com/en/tutorials/audio/scheduling/

Загляните на этот сайт, чтобы узнать больше Web Audio API, он был разработан, чтобы делать именно то, что вам нужно.

Ответ 5

Я использую этот способ в работе: "Забудьте об общих петлях" в этом случае и используйте эту комбинацию "setInterval", включая "setTimeOut" s:

    function iAsk(lvl){
        var i=0;
        var intr =setInterval(function(){ // start the loop 
            i++; // increment it
            if(i>lvl){ // check if the end round reached.
                clearInterval(intr);
                return;
            }
            setTimeout(function(){
                $(".imag").prop("src",pPng); // do first bla bla bla after 50 millisecond
            },50);
            setTimeout(function(){
                 // do another bla bla bla after 100 millisecond.
                seq[i-1]=(Math.ceil(Math.random()*4)).toString();
                $("#hh").after('<br>'+i + ' : rand= '+(Math.ceil(Math.random()*4)).toString()+' > '+seq[i-1]);
                $("#d"+seq[i-1]).prop("src",pGif);
                var d =document.getElementById('aud');
                d.play();                   
            },100);
            setTimeout(function(){
                // keep adding bla bla bla till you done :)
                $("#d"+seq[i-1]).prop("src",pPng);
            },900);
        },1000); // loop waiting time must be >= 900 (biggest timeOut for inside actions)
    }

PS: Поймите, что реальное поведение (setTimeOut): все они начнутся в одно и то же время "три bla bla bla начнут отсчитывать в тот же момент", поэтому сделайте другой тайм-аут, чтобы организовать выполнение.

PS 2: пример цикла синхронизации, но для циклов реакции вы можете использовать события, обещая асинхронное ожидание.

Ответ 6

Задача цикла setTimeout с решением

// it will print 5 times 5.
for(var i=0;i<5;i++){
setTimeout(()=> 
console.log(i), 
2000)
}               // 5 5 5 5 5

// improved using let
for(let i=0;i<5;i++){
setTimeout(()=> 
console.log('improved using let: '+i), 
2000)
}

// improved using closure
for(var i=0;i<5;i++){
((x)=>{
setTimeout(()=> 
console.log('improved using closure: '+x), 
2000)
})(i);
} 

Ответ 7

Используйте setInterval()

setInterval(function(){
 alert("Hello"); 
}, 3000);

Выше будет выполнено alert("Hello"); каждые 3 секунды.

Ответ 8

Используйте let вместо var в коде:

for(let i=1;i<=5;i++){setTimeout(()=>{console.log(i)},1000);}

Ответ 9

Я думаю, что лучше завершить тайм-аут в конце функции.

function main(){
    var something; 
    make=function(walkNr){
         if(walkNr===0){
           // var something for this step      
           // do something
         }
         else if(walkNr===1){
           // var something for that step 
           // do something different
         }

         // ***
         // finally
         else if(walkNr===10){
           return something;
         }
         // show progress if you like
         setTimeout(funkion(){make(walkNr)},15,walkNr++);  
   }
return make(0);
}   

Эти три функции необходимы, потому что vars во второй функции каждый раз будут перезаписаны значением по умолчанию. Когда указатель программы достигает значения setTimeout, один шаг уже рассчитан. Тогда просто экран нужно немного времени.

Ответ 10

Следующий код работает отлично

for (var i = 1; i <= 10; i++) <br>{ <br>
    setTimeout(function() { console.log(i); }, 1000*i);     
}

Что дает вам результат как 6 6 6 6 6