Saya sedang mengerjakan program musik yang membutuhkan banyak elemen JavaScript untuk disinkronkan dengan yang lain. Saya telah menggunakan setInterval
, yang bekerja dengan sangat baik pada awalnya. Namun, seiring waktu, elemen-elemen tersebut secara bertahap menjadi tidak sinkron yang berdampak buruk dalam program musik.
Saya telah membaca online yang setTimeout
lebih akurat, dan Anda bisa memiliki setTimeout
loop entah bagaimana. Namun, saya belum menemukan versi generik yang menggambarkan bagaimana hal ini dimungkinkan.
Pada dasarnya saya memiliki beberapa fungsi seperti:
//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);
Ini bekerja dengan sangat baik, pada awalnya, tetapi selama sekitar satu menit, suara menjadi terasa tidak sinkron saat saya membaca setInterval
. Saya telah membaca bahwa setTimeout
bisa lebih akurat secara konsisten.
Bisakah seseorang menunjukkan kepada saya contoh dasar penggunaan setTimeout
untuk mengulang sesuatu tanpa batas? Atau, jika ada cara untuk mendapatkan hasil yang lebih sinkron dengan setInterval
atau bahkan dengan fungsi lain, beri tahu saya.
sumber
setTimeout
Anda dapat menghitung berapa lama penundaan itu benar-benar menyesuaikan waktu untuk batas waktu berikutnya.requestAnimationFrame
? Anda hanya perlu merujuk waktu audio tersebut setiap kalirequestAnimationFrame
callback Anda berjalan.Jawaban:
Anda dapat membuat
setTimeout
loop menggunakan rekursi:function timeout() { setTimeout(function () { // Do Something Here // Then recall the parent function to // create a recursive loop. timeout(); }, 1000); }
Masalahnya dengan
setInterval()
dansetTimeout()
adalah bahwa tidak ada jaminan kode Anda akan berjalan dalam waktu yang ditentukan. Dengan menggunakansetTimeout()
dan memanggilnya secara rekursif, Anda memastikan bahwa semua operasi sebelumnya di dalam waktu tunggu selesai sebelum iterasi kode berikutnya dimulai.sumber
setInterval
?setInterval()
dijalankan ulang, variabel dan / atau data Anda bisa jadi tidak sinkron dengan sangat cepat. Jika saya ajaxing untuk data misalnya, dan server membutuhkan waktu lebih dari 1 detik untuk merespons, menggunakansetInterval()
data saya sebelumnya tidak akan menyelesaikan pemrosesan sebelum operasi berikutnya dilanjutkan. Dengan pendekatan ini, tidak ada jaminan bahwa fungsi Anda akan dimulai setiap detik. Namun, dijamin bahwa data Anda sebelumnya akan selesai diproses sebelum interval berikutnya dimulai.Hanya untuk melengkapi. Jika Anda perlu meneruskan variabel dan mengulanginya, Anda dapat melakukannya seperti ini:
function start(counter){ if(counter < 10){ setTimeout(function(){ counter++; console.log(counter); start(counter); }, 1000); } } start(0);
Keluaran:
1 2 3 ... 9 10
Satu baris per detik.
sumber
Mengingat tidak ada waktu yang akan sangat akurat, salah satu cara untuk menggunakan
setTimeout
agar sedikit lebih akurat adalah menghitung berapa lama penundaan sejak iterasi terakhir, dan kemudian menyesuaikan iterasi berikutnya yang sesuai. Sebagai contoh: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); }
Jadi pertama kali akan menunggu (setidaknya) 1000 ms, ketika kode Anda dieksekusi, mungkin agak terlambat, katakanlah 1046 ms, jadi kami mengurangi 46 ms dari penundaan kami untuk siklus berikutnya dan penundaan berikutnya adalah hanya 954 ms. Ini tidak akan menghentikan pengatur waktu agar tidak bekerja terlambat (yang diharapkan), tetapi membantu Anda menghentikan penundaan agar tidak menumpuk. (Catatan: Anda mungkin ingin memeriksa
thisDelay < 0
yang artinya penundaan itu lebih dari dua kali lipat penundaan target Anda dan Anda melewatkan satu siklus - terserah Anda bagaimana Anda ingin menangani kasus itu).Tentu saja, ini mungkin tidak akan membantu Anda menjaga beberapa pengatur waktu tetap sinkron, dalam hal ini Anda mungkin ingin mengetahui cara mengontrol semuanya dengan pengatur waktu yang sama.
Jadi melihat kode Anda, semua penundaan Anda adalah kelipatan 500, jadi Anda dapat melakukan sesuatu seperti ini:
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); }
sumber
Cara terbaik untuk menangani pengaturan waktu audio adalah dengan Api Audio Web, ia memiliki jam terpisah yang akurat terlepas dari apa yang terjadi di utas utama. Ada penjelasan bagus, contoh, dll dari Chris Wilson di sini:
http://www.html5rocks.com/en/tutorials/audio/scheduling/
Silakan melihat-lihat situs ini untuk lebih banyak API Audio Web, itu dikembangkan untuk melakukan apa yang Anda cari.
sumber
setTimeout
berkisar dari tidak cukup hingga sangat rumit. Menggunakan fungsi asli sepertinya ide yang jauh lebih baik. Jika API tidak memenuhi tujuan Anda, maka saya akan merekomendasikan untuk mencoba menemukan perpustakaan penjadwalan pihak ketiga yang andal.Menggunakan
setInterval()
setInterval(function(){ alert("Hello"); }, 3000);
Di atas akan dijalankan
alert("Hello");
setiap 3 detik.sumber
Sesuai dengan kebutuhan Anda
Kami memiliki contoh berikut yang dapat membantu Anda
var itr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; var interval = 1000; //one second itr.forEach((itr, index) => { setTimeout(() => { console.log(itr) }, index * interval) })
sumber
Saya menggunakan cara ini dalam kehidupan kerja: "Lupakan loop umum" dalam kasus ini dan gunakan kombinasi "setInterval" ini termasuk "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: Pahami bahwa perilaku sebenarnya dari (setTimeOut): mereka semua akan mulai dalam waktu yang sama "tiga bla bla bla akan mulai menghitung mundur pada saat yang sama" jadi buat batas waktu yang berbeda untuk mengatur eksekusi.
PS 2: contoh untuk putaran waktu, tetapi untuk loop reaksi Anda dapat menggunakan acara, janji asinkron menunggu ..
sumber
// 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); }
sumber
Seperti yang ditunjukkan orang lain, API Audio Web memiliki pengatur waktu yang lebih baik.
Tetapi secara umum, jika peristiwa ini terjadi secara konsisten, bagaimana jika Anda menempatkan semuanya pada timer yang sama? Saya sedang memikirkan tentang cara kerja sequencer langkah .
Secara praktis, mungkinkah terlihat seperti ini?
var timer = 0; var limit = 8000; // 8000 will be the point at which the loop repeats var drumInterval = 8000; var chordInterval = 1000; var bassInterval = 500; setInterval(function { timer += 500; if (timer == drumInterval) { // Do drum stuff } if (timer == chordInterval) { // Do chord stuff } if (timer == bassInterval) { // Do bass stuff } // Reset timer once it reaches limit if (timer == limit) { timer = 0; } }, 500); // Set the timer to the smallest common denominator
sumber
function appendTaskOnStack(task, ms, loop) { window.nextTaskAfter = (window.nextTaskAfter || 0) + ms; if (!loop) { setTimeout(function() { appendTaskOnStack(task, ms, true); }, window.nextTaskAfter); } else { if (task) task.apply(Array(arguments).slice(3,)); window.nextTaskAfter = 0; } } for (var n=0; n < 10; n++) { appendTaskOnStack(function(){ console.log(n) }, 100); }
sumber
Saya pikir lebih baik timeout di akhir fungsi.
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); }
Ketiga fungsi ini diperlukan karena vars di fungsi kedua akan ditimpa dengan nilai default setiap saat. Ketika penunjuk program mencapai setTimeout, satu langkah sudah dihitung. Maka hanya layar yang membutuhkan sedikit waktu.
sumber
Gunakan let sebagai ganti var dalam kode:
for(let i=1;i<=5;i++){setTimeout(()=>{console.log(i)},1000);}
sumber