web-dev-qa-db-ja.com

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);

最初は非常にうまく機能しますが、約1分間で、setIntervalを使用して読み取りを行うと、音が著しく同期しなくなります。setTimeoutの方が一貫して正確であることがわかりました。

68
user3084366

再帰を使用してsetTimeoutループを作成できます。

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

setInterval()setTimeout()の問題は、指定した時間にコードが実行される保証がないことです。 setTimeout()を使用して再帰的に呼び出すことにより、コード内の次の反復が始まる前に、タイムアウト内の以前のすべての操作が完了することを保証します。

149
War10ck

補足のみ。変数を渡して反復する必要がある場合は、次のようにすることができます。

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

出力:

1
2
3
...
9
10

1秒に1行。

22
João Paulo

どちらの時間も非常に正確ではないので、setTimeoutをもう少し正確に使用する1つの方法は、最後の反復からの遅延時間を計算し、次の反復を適切に調整することです。例えば:

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を確認することをお勧めします。これは、遅延がターゲット遅延の2倍以上であり、サイクルを見逃したことを意味します-そのケースの処理方法はあなた次第です)。

もちろん、これはおそらくいくつかのタイマーの同期を維持するのに役立ちません。その場合、同じタイマーでそれらすべてを制御する方法を見つけたいかもしれません。

コードを見ると、遅延はすべて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);
}
11
Matt Burland

オーディオタイミングを処理する最良の方法は、Web Audio APIを使用することです。メインスレッドで何が起こっているかに関係なく、正確な独立したクロックがあります。クリス・ウィルソンからの素晴らしい説明、例などがここにあります:

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

より多くのWeb Audio APIについては、このサイトをご覧ください。これは、あなたが望んでいることを正確に行うために開発されました。

5
Bing

ワークライフでこの方法を使用します。この場合は「一般的なループを忘れて」、「setInterval」のこの組み合わせを使用すると「setTimeOut」が含まれます。

    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)の実際の動作を理解してください:それらはすべて「3 bla bla blaが同じ瞬間にカウントダウンを開始する」同じ時間に開始するので、実行を調整するために異なるタイムアウトを作成します。

PS 2:タイミングループの例ですが、リアクションループではイベントを使用できます。asyncawaitをお約束します。

1

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);
} 
0
Vahid Akhtar

setInterval() を使用します

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

上記は3秒ごとにalert("Hello");を実行します。

0
Pedro Lobito