Ordre d'exécution de plusieurs fonctions setTimeout () avec le même intervalle

Considérez le code Javascript suivant:

function(){ setTimeout(function() { $("#output").append(" one "); }, 1000); setTimeout(function() { $("#output").append(" two "); }, 1000); } 

Vous pouvez également voir cet exemple sur jsfiddle .

Puis-je être sûr que la valeur de #output est toujours "one two" , dans cet ordre? Habituellement, je traiterais ce problème comme ceci:

 function(){ setTimeout(function() { $("#output").append(" one "); $("#output").append(" two "); }, 1000)); } 

Mais je ne peux pas le faire de cette façon parce que je reçois des messages d'un serveur qui me dit quelle fonction exécuter (dans cet exemple, append "one" ou append "two" ), que je dois exécuter avec un petit délai.

J'ai déjà testé ce code dans Internet Explorer 9, Firefox 14, Chrome 20 et Opera 12, et la sortie était toujours "one two" , mais je peux être sûr que ce sera toujours le cas?

La spécification est ici .

Mon interprétation de setTimeout étape 8, dans la section 7.3, est que le mandat d'exécution est censé être garanti.

Cependant, j'ai étudié ce problème, car lorsque la fenêtre a été réduite au maximum et ensuite optimisée dans Chrome, je trouvais que les délais d'attente dans des événements provenant de sources externes (comme les websockets ou les webworkers) étaient exécutés dans le mauvais ordre. Je suppose que c'est un bug de navigateur et nous l'espérons être corrigé bientôt.

Jouez avec ça dans votre violon

 $(document).ready(function() { setTimeout(function() { $("#output").append(" one "); }, 1000); }); $(document).ready(function() { setTimeout(function() { $("#output").append(" two "); }, 999); });​ 

Et vous verrez que les deux

 output: one two output: two one 

Sont possibles. Donc, Speransky est juste que vous ne pouvez pas compter sur vos délais d'exécution dans le même ordre toujours.

Notez que j'ai changé une fois avec 1 ms pour montrer que le délai d'attente de 1000 ms peut être exécuté avant le délai de 999 ms.

EDIT: Le code ci-dessous peut retarder l'exécution sans possibilité de two d'être imprimés avant one

 function(){ setTimeout(function() { $("#output").append(" one "); setTimeout(function() { $("#output").append(" two "); }, 100); }, 1000); } 

Oui, car le code javascript est exécuté dans un seul thread, tous les événements asynchrones, comme le click , mousemove , sont mis en file d'attente pour s'exécuter. Lorsque vous appelez setTimeout , le moteur insère une minuterie dans sa file d'attente pour l'exécuter à l'avenir, au moins après un delay . Donc, les deux setTimeout génèrent deux temporisateurs, l'un après l'autre.

Vous pouvez regarder comment fonctionnent les temporisateurs Javascript par John Resig.

Oui, la sortie sera toujours "one two" .

Parce que le premier setTimeout fonctionne toujours avant le second setTimeout , s'ils ont un même délai, alors la fonction de rappel du premier sera toujours exécutée avant la fonction de rappel de la seconde.

Non, vous ne pouvez pas être sûr. C'est de façon asynchrone.

Mais en fait, cela sera probablement vrai, en raison de la réalisation du mécanisme dans les navigateurs.

Mettre à jour
J'ai mis à jour votre violon avec cette méthode. Vérifiez le ici

Qu'en est-il de cette méthode – Obtenez une liste de choses à faire à partir de votre serveur –

 //Example - append one, append two var appendList = ['one', 'two'] //then do this appendList.forEach(function(item, index){ setTimeout(function(){ $('#output').append(item) }, index * 50 + 1000); }); 

De cette façon, vous décidez de la séquence.

Si les événements sont synchrones, il existe la fonction Continuum pour exécuter les fonctions en séquence:

 function keyedSequence(key, fn) { fn = fn || this; key.push({fn:fn}); return function() { for(var i=0, n, full=1; i<key.length; i++) { n = key[i]; if(n.fn == fn) { if(!n.called) n.called = 1, n.args = key.slice.call(arguments); if(!full) break } if(!n.called) full = 0 } if(full) for(i=0; i<key.length; i++) n = key[i], key[i] = {fn:n.fn}, n.fn.apply(n, n.args); } } Function.prototype.seq = keyedSequence; 

Vous fournissez un tableau vide comme clé. Les fonctions cliquées avec la même clé seront regroupées.

 window.onload = function() { var key = []; document.getElementById("test1").addEventListener('click', function1.seq(key), false); document.getElementById("test2").addEventListener('click', function2.seq(key), false); } 

Cliquez sur test2 , puis cliquez sur test1 et l'ordre d'exécution est encore function1 puis function2 .

Une autre façon de l'appeler est:

 window.onload = function() { var key = []; document.getElementById("test1").addEventListener('click', keyedSequence(key, function1), false); document.getElementById("test2").addEventListener('click', keyedSequence(key, function2), false); }