Des délais d'attente égaux sont-ils exécutés dans l'ordre en Javascript?

Supposons que je le fasse

setTimeout(foo, 0); ... setTimeout(bar, 0); 

Puis-je être sûr que foo va commencer à s'exécuter avant la barre? Que faire si au lieu de 0 j'utilise un délai de 1, 10 ou 100 pour la barre?

Des expériences simples montrent que, dans le cas de valeurs de temporisation égales, les cibles de temporisation sont exécutées dans le même ordre que les setTimeouts eux-mêmes, mais est-il sûr de s'appuyer sur ce comportement?

J'ai lu le code source de Firefox, et au moins pour ce navigateur, il existe une garantie séquentielle pour les délais spécifiés dans l'ordre de non-décrochage. Sinon, tous les paris sont désactivés.

Plus précisément, si dans un contexte d'exécution donné, vous définissez un délai d'attente pour n, puis un pour m, où n <= m, les cibles seront exécutées dans l'ordre où les délais sont définis.

Mais ne prenez pas ma parole pour cela. Je crois que l'implémentation de la fenêtre est dans nsGlobalWindow.cpp, et la méthode qui décide effectivement où les délais d'attente dans la file d'exécution est appelée InsertTimeoutIntoList . Il semble que la méthode parcourt la file vers l'arrière en recherchant le premier délai qui est inférieur ou égal au délai imparti et insère le délai imparti après.

Bien sûr, lorsque le délai d'attente est réglé, l'heure d'horloge actuelle est ajoutée à la valeur de temporisation. C'est pourquoi les valeurs de temporisation doivent être dans l'ordre de non-décrochage pour que les cibles soient exécutées en séquence.

Il n'est pas sûr de s'appuyer sur ce comportement. J'ai écrit un script de test qui planifie un certain nombre de fonctions (et, à leur tour, planifient également un certain nombre de fonctions), tout en utilisant setTimeout (…, 0), et l'ordre dans lequel les fonctions ont été appelées n'était pas toujours le même que le Ordre dans lequel SetTimeout a été appelé (au moins dans Chrome 11, que j'avais l'habitude d'exécuter le script).

Vous pouvez voir / exécuter le script ici: http://jsfiddle.net/se9Jn/ (le script utilise YUI pour la compatibilité entre navigateurs, mais Y.later utilise setTimeout en interne).

Notez que si vous exécutez simplement le script et regardez fixement la console, vous ne verrez probablement pas une commande offensante. Mais si vous démarrez le script, passez à un autre onglet, chargez des pages et revenez à la page de test, vous devriez voir des erreurs sur les rappels hors service dans la console.

Si vous avez besoin d'une commande garantie, je recommande de programmer la fonction suivante à la fin de la fonction précédente:

 setTimeout(foo, 0); ... function foo() { ... setTimeout(bar, 0); } 

Bref, ne comptez pas sur cela. Regardez cela .

Il y a beaucoup d'informations sur cette figure pour digérer, mais la compréhension complète vous donnera une meilleure compréhension de l'exécution asynchrone de Javascript.

La réponse est: Non, l'ordre d'exécution n'est pas garanti. J'ai parfois vu des commandes non FIFO dans chrome 40, surtout si je fais une pause dans le débogueur alors que les délais sont en attente. J'ai également eu une observation rare dans la nature – c'était la seule explication plausible d'un incident que j'ai enquêté.

Si vous avez besoin d'un ordre d'exécution garanti, au lieu de setTimeout(callback, 0) vous pouvez le faire:

 var queue = []; function handleQueue() { queue.shift()(); } function queueCallback(callback) { queue.push(callback); setTimeout(handleQueue, 0); } 

Maintenant, pour garantie, vous pouvez:

 queueCallback(foo); ... queueCallback(bar); 

Il y a un certain minimum que le délai peut effectivement être, et cela dépend beaucoup du système d'exploitation, du navigateur, de l'activité du navigateur et de la charge de l'ordinateur. J'ai tendance à ne pas aller au-dessous de 20 ms car je pense que quelque chose de moins que cela ne fait aucune différence.

Lorsque vous mettez deux retards égaux, cela ne signifie pas nécessairement que cela se produira dans cet ordre.

Si vous voulez vous assurer que cela se fera dans l'ordre, j'ai tendance à faire quelque chose comme ceci:

 setTimeout(function() { foo(); setTimeout(bar, 20) }, 20); 

Cela garantira toujours l'ordre.

Si vous utilisez Firefox, pour vous assurer que votre javascript est en fait multithread, vous pouvez consulter le WebWorker, qui est pris en charge sur les navigateurs les plus récents, mais pas sur IE.