Comment JavaScript gère-t-il les réponses AJAX en arrière-plan?

139

Puisque JavaScript s'exécute dans un seul thread, après qu'une requête AJAX est faite, que se passe-t-il réellement en arrière-plan? Je voudrais avoir un aperçu plus approfondi de cela, est-ce que quelqu'un peut nous éclairer?

aziz punjani
la source
6
Une assez bonne description est ici: stackoverflow.com/questions/2914161/ajax-multi-threaded
Jonathan M
3
Le code JavaScript est à thread unique (sauf pour les travailleurs Web), mais pas le navigateur qui exécute le moteur JavaScript ...
Juan Mendes
@JuanMendes Est-ce que JavaScript s'exécute dans un thread tandis que la file d'attente d'événements s'exécute dans un autre thread?
Shaun Luttin
1
@ShaunLuttin Non, c'est la file d'attente des événements qui lance JavaScript
Juan Mendes

Réponses:

213

Sous les couvertures, javascript a une file d'attente d'événements. Chaque fois qu'un thread d'exécution javascript se termine, il vérifie s'il existe un autre événement dans la file d'attente à traiter. Si tel est le cas, il le retire de la file d'attente et déclenche cet événement (comme un clic de souris, par exemple).

Le réseau de code natif qui se trouve sous l'appel ajax saura quand la réponse ajax est terminée et un événement sera ajouté à la file d'attente d'événements javascript. La façon dont le code natif sait quand l'appel ajax est effectué dépend de l'implémentation. Il peut être implémenté avec des threads ou il peut également être lui-même piloté par des événements (cela n'a pas vraiment d'importance). Le point de l'implémentation est que lorsque la réponse ajax est terminée, un certain code natif saura que c'est fait et mettra un événement dans la file d'attente JS.

Si aucun Javascript n'est en cours d'exécution à ce moment, l'événement sera immédiatement déclenché, ce qui exécutera le gestionnaire de réponse ajax. Si quelque chose est en cours d'exécution à ce moment-là, l'événement sera traité lorsque le thread d'exécution javascript actuel se terminera. Il n'y a pas besoin d'interroger le moteur javascript. Lorsqu'un morceau de Javascript finit de s'exécuter, le moteur JS vérifie simplement la file d'attente d'événements pour voir s'il y a autre chose qui doit s'exécuter. Si tel est le cas, il fait sortir l'événement suivant de la file d'attente et l'exécute (en appelant une ou plusieurs fonctions de rappel enregistrées pour cet événement). Si rien n'est dans la file d'attente d'événements, l'interpréteur JS a du temps libre (garbage collection ou inactif) jusqu'à ce qu'un agent externe mette autre chose dans la file d'attente d'événements et la réveille.

Étant donné que tous les événements extérieurs passent par la file d'attente des événements et qu'aucun événement n'est jamais déclenché pendant que javascript exécute réellement autre chose, il reste un thread unique.

Voici quelques articles sur les détails:

jfriend00
la source
Merci pour ça. Je soupçonnais que c'était le cas, mais bon à savoir avec certitude. J'ai une boucle for, dans laquelle j'envoie beaucoup de requêtes «ajax». Dans mon gestionnaire (pour chaque requête - renvoyée dans un ordre arbitraire), j'exécute du code qui peut prendre un certain temps. Bon à savoir, cela devrait certainement fonctionner.
iPadDeveloper2011
4
@telandor - les événements sont exécutés dans l'ordre FIFO (il est possible qu'il y ait des exceptions de cas de pointe, mais l'intention est FIFO). Certains événements sont traités légèrement différemment. Par exemple, les événements mousemove ne s'accumulent pas dans la file d'attente (probablement parce qu'ils pourraient facilement déborder de la file d'attente). Lorsque la souris bouge et qu'un événement mousemove est déjà dans la file d'attente et qu'il n'y a pas d'autres événements plus récents dans la file d'attente, il est mis à jour avec la dernière position plutôt qu'un nouvel événement ajouté. Je suppose que les événements de minuterie d'intervalle sont probablement également traités spécialement pour éviter qu'ils ne s'accumulent dans la file d'attente.
jfriend00
2
@telandor - De quoi avez-vous besoin d'expliquer davantage? C'est FIFO. J'ai ajouté quelques articles de référence supplémentaires à ma réponse. Les seules exécutions de FIFO dont je suis au courant sont des événements déclenchés immédiatement. Vous appelez .focus()un élément et cela déclenche quelques autres événements tels qu'un événement "flou" sur l'élément avec le focus. Cet événement de flou se produit de manière synchrone et ne passe pas par la file d'attente d'événements, il se produirait donc immédiatement avant d'autres choses qui pourraient se trouver dans la file d'attente d'événements. En pratique, je n'ai jamais trouvé que c'était une préoccupation pratique.
jfriend00
2
@telandor - Il n'y a pas plusieurs files d'attente par document de navigateur. Il y a une file d'attente et tout entre / sort en série FIFO. Ainsi, les délais d'attente et les réponses ajax, les événements de souris et les événements de clavier vont tous dans la même file d'attente. Celui qui est mis dans la file d'attente en premier est exécuté en premier.
jfriend00
1
@CleanCrispCode - Merci. Je l'ai ajouté comme référence utile à ma réponse.
jfriend00
16

Vous pouvez trouver ici une documentation très complète sur la gestion des événements en javascript.
Il est écrit par un gars travaillant sur l'implémentation javascript dans le navigateur Opera.

Plus précisément, regardez les titres: "Event Flow", "Event Queuing" et "Non-user Events": vous apprendrez que:

  1. Javascript s'exécute dans un seul thread pour chaque onglet ou fenêtre du navigateur.
  2. Les événements sont mis en file d'attente et exécutés séquentiellement.
  3. XMLHttpRequest sont exécutés par l'implémentation et les rappels sont exécutés à l'aide de la file d'attente d'événements.

Remarque: le lien d'origine était: lien , mais il est maintenant mort.

qwertzguy
la source
1

Je veux élaborer un peu, concernant l'implémentation ajax mentionnée dans les réponses.

Bien que (régulier) exécution Javascript est pas multi-thread - comme il est indiqué bien dans les réponses ci - dessus - cependant , la manipulation réelle du AJAX responses(ainsi que le traitement de la demande) est pas Javascript, et - le plus souvent - est multi-thread. (voir l' implémentation de la source chrome de XMLHttpRequest dont nous parlerons ci-dessus)

et je vais vous expliquer, prenons le code suivant:

var xhr = new XMLHttpRequest();

var t = Date.now;
xhr.open( "GET", "https://swx.cdn.skype.com/shared/v/1.2.15/SkypeBootstrap.min.js?v="+t(), true );

xhr.onload = function( e ) {
		console.log(t() + ': step 3');
    
    alert(this.response.substr(0,20));
};
console.log(t() + ': step 1');
xhr.send();
console.log(t() + ': step 2');

after an AJAX request is made(- après l'étape 1), puis pendant l'exécution de votre code js (étape 2 et après), le navigateur commence le vrai travail de: 1. formatage d'une requête tcp 2. ouverture d'un socket 3. envoi d'en-têtes 4. prise de contact 5. envoi body 6. réponse en attente 7. lecture des en-têtes 8. lecture du corps etc. toute cette implémentation est généralement exécutée dans un thread différent en parallèle de l'exécution de votre code js. pour un exemple, l'implémentation de chrome mentionnée utilise Threadable Loader go digg-into 😉, (vous pouvez également avoir une impression en regardant l'onglet réseau d'un chargement de page, vous verrez quelques requêtes simultanées).

en conclusion, je dirais qu'au moins la plupart de vos opérations d'E / S peuvent être effectuées simultanément / asynchrone (et vous pouvez en profiter en utilisant un await par exemple). mais toutes les interactions avec ces opérations (l'émission, l'exécution du rappel js) sont toutes synchrones.

shmulik friedman
la source