web-dev-qa-db-fra.com

Comment Javascript est-il threadé?

J'ai une question sur la nature unique de Javascript.

console.log("1");
setTimeout(function(){console.log("2");},3000);
console.log("3");
setTimeout(function(){console.log("4");},1000);

Le résultat de ce code est 1 3 4 2. Comme vous le voyez, 4 vient après 2, ce qui me fait penser que, dans un environnement à thread unique, 2 n'aurait pas dû suivre 4 Sinon, comment se fait-il que JS sache que la seconde setTimeout devrait se terminer avant la première? Ne devrait-il pas y avoir deux threads qui fonctionnent simultanément pour compléter les deux setTimeouts afin de notifier EventLoop?

31
Tarik

JavaScript (dans les navigateurs) ne s'exécute pas simultanément2.

Au plus one des rappels setTimeout peuvent s'exécuter simultanément - car il existe one un contexte d'exécution JavaScript ou un "thread".

Cependant, le "prochain délai d'expiration planifié" à exécuter est toujours exécuté .. suivant. Le "4" s'exécute avant le "2" car il était prévu que soit exécuté plus tôt. Les délais d'attente étaient effectivement planifiés à partir de au même moment (aucune opération ne bloquait), mais "2" avait un intervalle beaucoup plus long.

L'implémentation sous-jacente peut utiliser des threads1 - mais JavaScript dans le même contexte global ne ne s'exécute pas en même temps et garantit le comportement de consistent et atomic entre tous les rappels.


1 Ou peut-être pas; cela peut être géré sans aucun thread dans une implémentation select/poll.

2 Dans le même contexte: onglet/fenêtre, WebWorker, contrôle du navigateur d’hôte. Par exemple, alors que WebWorkers est exécuté simultanément, il le fait dans des contextes différents et suit le même modèle asynchrone (utilisé par exemple par les minuteurs).

25
user2864740

Javascript exécute chaque ligne en séquence.

Alors vous avez dit à JS:

  • écrire 1: js writes 1
  • attendez 3 secondes puis écrivez 2: ok I'll wait 3 seconds...now what?
  • écrire 3: ok I'll write 3, by the way, the 3 seconds is not up.
  • attendez 1 seconde puis écrivez 4: ok I'll wait 1 second...

alors js attend .99999 secondes ... et écrit 4 

puis attend encore et écrit 2

11
Brian McGinity

Javascript utilise un élément appelé Eventloop pour les appels asynchrones . Le setTimeout est poussé vers EventLoop puisqu'il s'agit d'un rappel. et le thread principal continue de s'exécuter. Une fois la main terminée, EventLoop envoie les données à la pile principale. Ex:

console.log("1");
setTimeout(function(){console.log("2");},0);
console.log("3");
setTimeout(function(){console.log("4");},1000);

Lorsque le délai est égal à 0, la sortie du code sera, 

1 3 2 4

Depuis qu’il exécute d’abord les appels du Main, puis ramène les données d’Eventloop Modèle simultané et boucle d’événement

7
Siddaram H

le second paramètre de setTimeout prend le temps minimum après lequel la fonction de rappel (premier argument) doit être poussée sur la boucle d'événement, qui n'est rien d'autre qu'une file d'attente pour les fonctions de rappel. Cette file d'attente est utilisée pour démarrer réellement l'exécution.

Une fois que setTimeout est rencontré pour la première fois, la fonction est poussée à l'extérieur et on lui dit d'attendre 3 secondes avant de rentrer dans un monde à thread unique. La même chose se produit pour la seconde fonction de temporisation, mais il ne doit attendre que 1 seconde. Le point d'entrée dans ce monde à un seul thread est la file d'attente de rappel. JS Engine continue l'exécution normale comme si l'exécution avec settimeout était effectuée avec. Maintenant, une fois que 1 seconde a expiré, la fonction de seconde temporisation est ajoutée à la file d'attente et en attente d'exécution. Si la pile d'appels est vide à ce moment-là, la fonction est alors traitée (en supposant qu'il s'agisse du premier membre de la file d'attente) et "4" est imprimé. Maintenant, si 3 secondes ne se sont pas écoulées pendant ce temps, la fonction de premier timeout attend toujours quelque part à l'extérieur. Une fois que 3 secondes se sont écoulées, la fonction de rappel entre dans la file d'attente et, comme la pile d'appels est vide, elle s'exécute et "2" est imprimé.

Le navigateur a maintenant accès à plusieurs threads à partir du système d'exploitation (bien qu'il ne fournisse qu'un seul environnement threadé pour l'exécution de JS) Ces setTimeouts sont traités par un autre thread en arrière-plan.

Il y a une vidéo de Philips Robert qui explique admirablement les concepts de file d'attente et de boucle d'événement qui conduisent à "l'asynchrone" du javascript à un seul thread.

https://www.youtube.com/watch?v=8aGhZQkoFbQ

4
Nikhil Sahu

Voici les étapes: 

  1. Ajout de console.log (1) à la pile d’appels JS. temps (~ 0)

  2. L'exécuter. (imprime 1 dans la console) - heure (~ 0)

  3. Ajout de setTimeout (function () {console.log ("2");}, 3000); à la pile d'appels. - heure (~ 0)

  4. Déplacez-le dans la boucle d'événements et démarrez le chronomètre. - temps (3 sec)

Comme setTimeout est une fonction asynchrone, elle passera à la boucle d’événement.

  1. Ajout de console.log (3) à la pile d'appels JS. temps (~ 0)

  2. L'exécuter. (affiche 3 en console) temps (~ 0)

  3. Ajout de setTimeout (function () {console.log ("4");}, 1000); à la pile d'appels. temps (~ 0)

  4. Déplacez-le dans la boucle d'événements et démarrez le chronomètre. - temps (1 sec)

  5. Le chronomètre de 1 seconde est terminé. Il revient donc à la pile d’appels et est exécuté.

  6. Call Stack l'exécute. (imprime 4 dans la console) - heure (~ 0)

  7. Le chronomètre de 3 secondes est terminé. Il revient donc à la pile d'appels et est exécuté.

  8. Call Stack l'exécute. (imprime 2 dans la console) - heure (~ 0)

Nous appelons maintenant synchrone la pile d’appel JS qui ne peut exécuter qu’une chose à la fois.

J'aurais pu en faire un processus en 20 étapes mais pour faciliter la compréhension, 12 suffisent.

0
Aisha Hale