Cet article vous apporte des problèmes liés au mécanisme d'exécution de JavaScript, y compris des connaissances sur le monothreading JavaScript, la synchronisation et l'asynchronisme de JavaScript. J'espère qu'il sera utile à tout le monde.
Si vous voulez comprendre pourquoi JavaScript est monothread, nous devons commencer par quel travail JavaScript est utilisé.
En tant que langage de script pour les navigateurs, le but de JavaScript est que le navigateur interagisse avec les utilisateurs et exploite les éléments DOM, améliorant ainsi l'interaction et l'expérience des utilisateurs. JavaScript doit faire fonctionner l'élément DOM du navigateur, donc JavaScript ne peut pas devenir un langage multithread. Supposons un scénario si JavaScript est un langage multithread, deux threads gèrent un élément DOM en même temps. mettre à jour l'élément DOM, tandis que l'autre thread doit modifier et mettre à jour l'élément DOM. Il s'agit de supprimer le nœud de l'élément DOM. Lequel le navigateur doit-il utiliser ?
Vous ne pouvez faire la même chose qu'en même temps. En raison du fonctionnement des éléments DOM, le threading unique est le cœur et la caractéristique du langage JavaScript.
HTML5 propose le standard Web Worker, qui permet aux scripts JavaScript de créer plusieurs threads, mais les threads enfants sont entièrement contrôlés par le thread principal et ne doivent pas faire fonctionner le DOM. Même de tels changements ne changent pas la nature monothread de js.
Le mécanisme monothread de JavaScript fait qu'une seule chose peut être faite en même temps. Tout comme un groupe de personnes retirant de l'argent à un distributeur automatique, même s'il y a plus de gens derrière eux qui sont pressés, ils ne peuvent que faire la queue un par un et attendre que la première personne retire de l'argent avant que ce soit le tour de la personne suivante.
Mais cela fera que si la tâche précédente prend trop de temps, la tâche suivante attendra très longtemps. Par exemple, si nous devons charger une requête Ajax avec une très grande quantité de données, nous devrons attendre. le résultat correspondant de la demande avant de continuer. Descendez et effectuez les tâches suivantes.
Alors, comment devons-nous gérer cette situation ? Puisque nous ne pouvons pas modifier le mécanisme monothread de JavaScript, pouvons-nous suspendre temporairement certaines tâches à long terme et attendre que la tâche principale soit terminée avant d'exécuter ces tâches montées ? L'auteur de JavaScript a également pensé à cette façon. JavaScript comporte des tâches synchrones et des tâches asynchrones.
Les tâches synchrones signifient que les tâches sont mises en file d'attente sur le thread principal et que la tâche suivante doit attendre la fin de la tâche précédente avant de pouvoir être exécutée. Une tâche asynchrone signifie que la tâche n'entre pas dans le thread principal, mais entre dans la file d'attente des tâches pour attendre. La tâche qui entre dans la file d'attente des tâches n'entrera que si la « file d'attente des tâches » informe le thread principal qu'une tâche asynchrone peut être exécutée. Exécution du thread principal.
Toutes les tâches de synchronisation de JavaScript sont exécutées sur le thread principal, formant une pile d'exécution.
La file d'attente des tâches est basée sur le principe du premier entré, premier sorti. Les événements de la file d'attente avancée sont exécutés en premier et les événements de la dernière file d'attente sont exécutés plus tard.
Event Loop
Exécutez des tâches de synchronisation dans la pile d'exécution.
Lorsqu'il rencontre une tâche asynchrone, il n'attendra pas son résultat de retour. Il suspendra temporairement la tâche asynchrone et continuera à exécuter d'autres tâches synchrones.
Lorsque la tâche asynchrone donne des résultats, la tâche JavaScript sera ajoutée à la file d'attente des tâches. Les tâches ajoutées à la file d'attente des tâches ne seront pas exécutées immédiatement par rappel, mais attendront que le thread principal (pile d'exécution) soit inactif avant d'être ajoutées à la pile d'exécution pour l'exécution du rappel
En attente des tâches dans la pile d'exécution à exécuter.
Ajoutez la tâche dans la file d'attente des tâches à la pile d'exécution et exécutez-la.
À plusieurs reprises, cela forme une boucle infinie. (L'image ci-dessous provient d'Internet)
Après avoir appris Event Loop, jetons un coup d'œil à la question suivante :
setTimeout(function(){ console.log('setTimeout start') }); new Promise(function(resolve){ console.log('promise start'); resolve() }).then(function(){ console.log('promise then') }); console.log('script end');
Essayez d'analyser selon le mécanisme d'exécution JavaScript que nous venons d'apprendre ci-dessus
1. Première exécution synchronisation La tâche est exécutée jusqu'à setTimeout, mais setTimeout est une suspension temporaire de la tâche asynchrone, en attendant que le délai d'attente soit ajouté à la file d'attente des tâches.
2. Continuez et exécutez la nouvelle promesse. La nouvelle promesse contient les tâches de synchronisation et imprime "démarrage de la promesse".
3. Ajoutez .then à la file d'attente des tâches après avoir exécuté la résolution.
4. Après avoir exécuté console.log('script end'); imprimez "script end".
5. A ce moment, la tâche principale a été exécutée. Ajoutez la tâche asynchrone à la tâche principale et exécutez-la directement, imprimez "setTimeout start", puis ajoutez .then à la tâche principale, et imprimez "promise then".
Le résultat devrait donc être : promise start -> script end -> setTimeout start -> promise then ?
Après l'avoir exécuté personnellement dans le navigateur, le résultat n'est pas comme ça, mais promise start -> fin - > promis puis -> setTimeout start
Alors pourquoi les résultats ci-dessus sont-ils incohérents avec ce à quoi nous nous attendions ? Pourquoi setTimeout start est-il imprimé après la promesse ?
En fait, c'est parce que l'exécution asynchrone est également séquentielle. En fait, il est inexact d'utiliser des méthodes asynchrones et synchrones pour diviser l'ordre d'exécution des files d'attente de tâches. Il doit être divisé en microtâches et macrotâches.
Macro-tâche : code de script, setTimeout, setInterval
Micro-tâche : Promise, process.nextTick
Donc setTimeout est une tâche macro dans les tâches asynchrones. Promise est une microtâche dans les tâches asynchrones. Qu'il s'agisse d'une microtâche ou d'une macrotâche, elle entrera dans la file d'attente d'événements correspondante. Nous examinons ensuite un organigramme.
Comprenons-le un peu :
1. Exécuter des tâches macro (code de script)
2. Lorsqu'une micro-tâche est rencontrée lors de l'exécution d'une macro-tâche, la micro-tâche sera ajoutée à la file d'attente d'événements
3. Une fois l'exécution de la macro-tâche en cours terminée, la file d'attente d'événements de la micro-tâche sera affichée et toutes les micro-tâches qu'elle contient seront exécutées dans l'ordre
4. Après l'exécution toutes les micro-tâches, continuez La première étape est de boucler comme ça
C'est aussi le mécanisme de fonctionnement de javaScript. Combiné avec cela, nous ré-analyserons l'exemple ci-dessus.
1. Exécutez d'abord la tâche macro (code de script) et lorsque setTimeout est rencontré, ajoutez-la à la file d'attente d'événements de la tâche macro.
2. Continuez à exécuter la nouvelle promesse et imprimez "promise start".
3. Après avoir exécuté la résolution, .then est la microtâche et est ajoutée à la file d'attente d'événements de la microtâche.
4. Lors de l'exécution de console.log('script end'); imprimez "script end".
5. À ce stade, toutes les macro-tâches de ce tour ont été exécutées. À ce stade, vérifiez s'il y a des micro-tâches exécutables dans la file d'attente des événements des micro-tâches. dans la troisième étape. Ensuite, exécutez Et imprimez "promise then"
6. À ce moment, le premier tour de boucle d'événement est complètement terminé. Le prochain tour de boucle d'événement exécutera d'abord une tâche macro et constatera que la. setTimeout est ajouté à la file d'attente d'événements de la tâche macro. Exécutez et imprimez "setTimeout start"
N'oubliez pas que JavaScript est monothread, l'a toujours été, l'est et le sera dans le futur. Tous les discours sur le multi-threading sont des conneries.
Even Event Queue n'est pas seulement un moyen d'implémenter l'asynchrone, mais aussi un mécanisme d'exécution de js.
Il pourra être implémenté en utilisant JavaScript à l'avenir. Tout sera implémenté en utilisant JavaScript.
Recommandations associées : Tutoriel d'apprentissage Javascript
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!