Je travaille sur un programme musical qui nécessite plusieurs éléments JavaScript pour être synchronisés avec un autre. J'utilise setInterval
, qui fonctionne très bien au début. Cependant, avec le temps, les éléments deviennent progressivement désynchronisés, ce qui est mauvais dans un programme musical.
J'ai lu en ligne qui setTimeout
est plus précis, et vous pouvez avoir des setTimeout
boucles d'une manière ou d'une autre. Cependant, je n'ai pas trouvé de version générique qui illustre comment cela est possible.
En gros, j'ai quelques fonctions comme celles-ci:
//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);
Cela fonctionne très bien, au début, mais en l'espace d'une minute environ, les sons deviennent sensiblement désynchronisés au fur et à mesure que je l'ai lu setInterval
. J'ai lu que cela setTimeout
peut être plus précis.
Quelqu'un pourrait-il simplement me montrer un exemple de base d'utilisation setTimeout
pour boucler quelque chose indéfiniment? Sinon, s'il existe un moyen d'obtenir des résultats plus synchrones avec setInterval
ou même une autre fonction, veuillez me le faire savoir.
la source
setTimeout
vous pouvez calculer combien de temps le délai a vraiment été un ajustement du temps pour le prochain délai.requestAnimationFrame
? Vous auriez juste à référencer l'heure à laquelle l'audio est à chaque fois que votrerequestAnimationFrame
rappel s'exécute.Réponses:
Vous pouvez créer une
setTimeout
boucle en utilisant la récursivité:function timeout() { setTimeout(function () { // Do Something Here // Then recall the parent function to // create a recursive loop. timeout(); }, 1000); }
Le problème avec
setInterval()
etsetTimeout()
est qu'il n'y a aucune garantie que votre code s'exécutera dans le temps spécifié. En l'utilisantsetTimeout()
et en l'appelant de manière récursive, vous vous assurez que toutes les opérations précédentes dans le délai d'expiration sont terminées avant le début de la prochaine itération du code.la source
setInterval
?setInterval()
ré-exécution, vos variables et / ou données pourraient se désynchroniser très rapidement. Si j'ajaxe des données par exemple et que le serveur met plus de 1 seconde à répondre, l'utilisation desetInterval()
mes données précédentes n'aurait pas fini le traitement avant la poursuite de ma prochaine opération. Avec cette approche, il n'est pas garanti que votre fonction démarre toutes les secondes. Cependant, il est garanti que le traitement de vos données précédentes sera terminé avant le début du prochain intervalle.Seulement pour compléter. Si vous avez besoin de passer une variable et de l'itérer, vous pouvez faire comme ceci:
function start(counter){ if(counter < 10){ setTimeout(function(){ counter++; console.log(counter); start(counter); }, 1000); } } start(0);
Production:
1 2 3 ... 9 10
Une ligne par seconde.
la source
Étant donné qu'aucun temps ne sera très précis, une façon d'utiliser
setTimeout
pour être un peu plus précis est de calculer combien de temps le délai a duré depuis la dernière itération, puis d'ajuster l'itération suivante le cas échéant. Par exemple: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); }
Donc, la première fois qu'il attendra (au moins) 1000 ms, lorsque votre code sera exécuté, il se peut qu'il soit un peu en retard, disons 1046 ms, donc nous soustrayons 46 ms de notre délai pour le cycle suivant et le prochain délai sera seulement 954 ms. Cela n'empêchera pas la minuterie de se déclencher en retard (c'est normal), mais vous aidera à empêcher les retards de s'accumuler. (Remarque: vous voudrez peut-être vérifier
thisDelay < 0
ce qui signifie que le retard était plus du double de votre retard cible et que vous avez manqué un cycle - à vous de décider comment vous voulez gérer ce cas)Bien sûr, cela ne vous aidera probablement pas à synchroniser plusieurs minuteries.Dans ce cas, vous voudrez peut-être savoir comment les contrôler toutes avec la même minuterie.
Donc, en regardant votre code, tous vos retards sont un multiple de 500, vous pouvez donc faire quelque chose comme ceci:
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); }
la source
La meilleure façon de gérer la synchronisation audio est d'utiliser l'API Web Audio, elle dispose d'une horloge distincte qui est précise indépendamment de ce qui se passe dans le thread principal. Il y a une excellente explication, des exemples, etc. de Chris Wilson ici:
http://www.html5rocks.com/en/tutorials/audio/scheduling/
Jetez un œil sur ce site pour plus d'API Web Audio, il a été développé pour faire exactement ce que vous recherchez.
la source
setTimeout
vont d'insuffisant à horriblement surcomplexe. Utiliser une fonction native semble être une bien meilleure idée. Si l'API ne répond pas à votre objectif, je vous recommanderais d'essayer de trouver une bibliothèque de planification tierce fiable.Utilisation
setInterval()
setInterval(function(){ alert("Hello"); }, 3000);
Ce qui précède s'exécutera
alert("Hello");
toutes les 3 secondes.la source
Selon votre condition
nous avons l'exemple suivant qui peut vous aider
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) })
la source
J'utilise cette façon dans la vie professionnelle: "Oubliez les boucles communes" dans ce cas et utilisez cette combinaison de "setInterval" inclut "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: Comprenez que le comportement réel de (setTimeOut): ils commenceront tous dans le même temps "les trois bla bla bla commenceront le compte à rebours au même moment" alors faites un timeout différent pour organiser l'exécution.
PS 2: l'exemple pour la boucle de synchronisation, mais pour une boucle de réaction, vous pouvez utiliser des événements, promettez async wait ..
la source
// 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); }
la source
Comme quelqu'un d'autre l'a souligné, l'API Web Audio a une meilleure minuterie.
Mais en général, si ces événements se produisent de manière cohérente, que diriez-vous de les mettre tous sur la même minuterie? Je réfléchis au fonctionnement d'un séquenceur pas à pas .
Pratiquement, cela pourrait-il ressembler à quelque chose comme ça?
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
la source
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); }
la source
Je pense qu'il est préférable de temporiser à la fin de la fonction.
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); }
Ces trois fonctions sont nécessaires car les variables de la deuxième fonction seront écrasées par la valeur par défaut à chaque fois. Lorsque le pointeur de programme atteint le setTimeout, une étape est déjà calculée. Ensuite, juste l'écran a besoin d'un peu de temps.
la source
Utilisez let au lieu de var dans le code:
for(let i=1;i<=5;i++){setTimeout(()=>{console.log(i)},1000);}
la source