Maison  >  Article  >  interface Web  >  Mécanisme de fonctionnement JS : analyse de la synchronisation, de l'asynchrone et de la boucle événementielle (Event Loop)

Mécanisme de fonctionnement JS : analyse de la synchronisation, de l'asynchrone et de la boucle événementielle (Event Loop)

不言
不言original
2018-08-07 15:41:281444parcourir

Ce que cet article vous apporte, c'est l'analyse du mécanisme de fonctionnement de JS : synchronisation, asynchrone et boucle d'événement (Event Loop). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. Vous avez aidé.

1. Pourquoi JS est monothread

Une caractéristique majeure du langage Javascript est qu'il est monothread et ne peut faire que la même chose en même temps. Alors pourquoi JS ne peut-il pas être multithread ?

En tant que langage de script de navigateur, l'objectif principal de Javascript est d'interagir avec les utilisateurs et de faire fonctionner le DOM, ce qui détermine qu'il ne peut être qu'un seul thread, sinon cela entraînera des problèmes très complexes. problèmes de synchronisation. Par exemple : supposons que Javascript ait deux threads en même temps. Un thread ajoute du contenu à un certain nœud DOM et l'autre thread supprime un nœud. Dans ce cas, lequel le navigateur doit-il utiliser ?

Par conséquent, afin d'éviter toute complexité, Javascript est monothread depuis sa naissance. Cela est devenu la fonctionnalité essentielle de ce langage et ne changera pas à l'avenir.

Afin de profiter de la puissance de calcul des CPU multicœurs, HTML5 propose le standard Web Woker, 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 peut pas faire fonctionner le DOM. Par conséquent, cette nouvelle norme ne modifie pas la nature monothread de JavaScript.

2. Synchrone et asynchrone

Supposons qu'il existe une fonction A :

A(args...){...}

Synchronisation : Si l'appelant peut immédiatement obtenir le résultat attendu lors de l'appel de la fonction A, alors cette fonction est synchrone.

Asynchrone : Si lors de l'appel de la fonction A, l'appelant ne peut pas obtenir le résultat attendu immédiatement, mais doit l'obtenir dans le futur par certains moyens (temps, délai, déclenchement d'événements), alors cette fonction est asynchrone .

3. Comment JS implémente les opérations asynchrones

Bien que JS soit monothread, le noyau du navigateur est multithread Navigation Le navigateur s'ouvre. des threads supplémentaires pour certaines tâches fastidieuses. Différentes opérations asynchrones seront planifiées et exécutées par différents modules du noyau du navigateur. Par exemple, onlcik, setTimeout et ajax sont traités de différentes manières, respectivement, par le DOM dans le noyau du navigateur. Les modules Bingding, réseau et minuterie sont exécutés lorsque la tâche exécutée obtient le résultat en cours d'exécution, la fonction de rappel correspondante sera placée dans la file d'attente des tâches. Par conséquent, JS a toujours été monothread et c'est le navigateur qui implémente les opérations asynchrones.

Dans l'image ci-dessus, lorsque des requêtes DOM, des requêtes ajax, setTimeout et d'autres WebAPI sont rencontrées dans la pile d'appels, elles seront transmises à d'autres modules du noyau du navigateur pour le traitement, webkit En plus du moteur d'exécution Javascript, le noyau possède un module important appelé module webcoew. Pour les trois API mentionnées par WebAPI dans la figure, webcore fournit respectivement des modules de liaison DOM, de réseau et de minuterie pour gérer l'implémentation sous-jacente. Lorsque ces modules ont fini de traiter ces opérations, placez la fonction de rappel dans la file d'attente des tâches, puis attendez que les tâches de la pile soient exécutées avant d'exécuter la fonction de rappel dans la file d'attente des tâches.

Résumé :

1. Tous les codes doivent être exécutés via des appels dans la pile d'appels de fonction

2. Lorsque vous rencontrez les API mentionnées ci-dessus, elles seront transmises à d'autres modules du noyau du navigateur pour traitement

3 La fonction de rappel est stockée dans la file d'attente des tâches

4 , attendez que la tâche dans la pile d'appels soit exécutée, puis revenez pour exécuter la tâche dans la file d'attente des tâches

Le mécanisme d'exécution de JS est le suivant :

(1) Toutes les tâches de synchronisation sont exécutées sur le thread principal pour former une pile d'exécution.

(2) En plus du fil de discussion principal, il existe également une "file d'attente des tâches". Tant que la tâche asynchrone a le résultat de l'opération, un événement (fonction de rappel) est placé dans la « file d'attente des tâches ».

(3) Une fois que toutes les tâches de synchronisation dans la « pile d'exécution » sont terminées, le système lira la « file d'attente des tâches » pour voir quels événements s'y trouvent. Les tâches asynchrones correspondantes mettent fin à l’état d’attente. Entrez dans la pile d'exécution et démarrez l'exécution.

(4) Le fil de discussion principal ne cesse de répéter la troisième étape ci-dessus

File d'attente des tâches

Comme mentionné ci-dessus, accédez au file d'attente des tâches, alors qu'est-ce que la file d'attente des tâches exactement ? Par exemple

Dans le standard ES6, la file d'attente des tâches est divisée en macro-tâches (macro-tâche) et micro-tâches (micro-tâche)

1.macro-tâche comprend : le script (entier code), setTimeout, setInterval, setImmediate, I/O, rendu UI

2.micro-tâche comprend : process.nextTick, Promises, Object.observe, MutationObserver

L'ordre de la boucle d'événements est de démarrer la première boucle à partir du script, puis le contexte global entre dans la pile d'appels de fonction Lorsqu'il rencontre une macro-tâche, elle est transmise au module qui la gère. Après le traitement, la fonction de rappel est placée dans la file d'attente des macros. Lorsqu'elle rencontre une micro-tâche, sa fonction de rappel est également placée dans la file d'attente des micro-tâches. Jusqu'à ce que la pile d'appels de fonction soit effacée et qu'il ne reste que le contexte d'exécution global, toutes les micro-tâches commencent à être exécutées. Une fois que toutes les micro-tâches exécutables ont été exécutées. La boucle exécute à nouveau une file d'attente de tâches dans la macro-tâche, puis exécute toutes les micro-tâches après l'exécution, et la boucle continue ainsi.

Analysons ensuite le processus d'exécution :

(function test() {
    setTimeout(function() {console.log(4)}, 0);
    new Promise(function executor(resolve) {
        console.log(1);
        for( var i=0 ; i<10000 ; i++ ) {
            i == 9999 && resolve();
        }
        console.log(2);
    }).then(function() {
        console.log(5);
    });
    console.log(3);
})()

1 Le contexte global est poussé sur la pile et le code qu'il contient commence à être exécuté. .

2. Exécutez sur setTimeout, remettez-le au module timer en tant que macro-tâche, puis placez sa fonction de rappel dans sa propre file d'attente.

3. Exécutez sur l'instance Promise et poussez la Promise sur la pile. Le premier paramètre consiste à exécuter directement la sortie 1 dans la tâche en cours.

4. Exécutez le corps de la boucle, rencontrez la fonction de résolution, poussez-la dans la pile et retirez-la après l'exécution, changez le statut de la promesse en Réalisée, puis affichez 2

5. la méthode then, en tant que micro-tâche, entre dans la file d'attente des tâches Promise.

6. Continuez à exécuter le code et sortez 3.

7. Après la sortie de 3, le premier code de macrotâche est exécuté et toutes les microtâches de la file d'attente commencent à être exécutées. La fonction de rappel de Then est poussée sur la pile puis ressorte, produisant 5.

8. À ce moment, toutes les tâches micao ont été exécutées et le premier cycle se termine. Le deuxième tour de boucle commence à partir de la file d'attente des tâches de setTimeout. La fonction de rappel de setTimeout est poussée dans la pile puis ressorte. À ce moment, 4 est affiché.

Résumé :

1. Différentes tâches seront placées dans différentes files d'attente de tâches.

2. Exécutez d'abord la macro-tâche, attendez que la pile d'appels de fonction soit effacée, puis exécutez toutes les micro-tâches dans la file d'attente.

3. Attendez que toutes les micro-tâches soient exécutées, puis démarrez l'exécution à partir d'une file d'attente de tâches dans la macro-tâche, et la boucle continue ainsi.

4. Lorsqu'il y a plusieurs files d'attente de macro-tâches (micro-tâches), l'ordre de la boucle d'événements est exécuté dans l'ordre écrit dans la classification des macro-tâches (micro-tâches) ci-dessus.

Résumé :

Lorsque le moteur JS analyse le code JS, il crée un thread principal et une pile d'appels (appel -stack), lorsqu'une tâche d'une pile d'appels est traitée, les autres doivent attendre.

Lorsque certaines opérations asynchrones sont effectuées, elles seront transmises à d'autres modules du noyau du navigateur pour traitement (en prenant webkit comme exemple, c'est le module webcore après le traitement). est terminée, la tâche (fonction de rappel) mise dans la file d'attente des tâches.

Généralement, les fonctions de rappel de différentes tâches asynchrones seront placées dans différentes files d'attente de tâches. Une fois toutes les tâches de la pile d'appels exécutées, les tâches de la file d'attente de tâches (fonctions de rappel) sera exécuté. )

Articles connexes recommandés :

Utilisation de ce mot-clé en javascript (avec code)

Quels sont les types de données js ? Résumé des types de données de js

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn