Maison > interface Web > Questions et réponses frontales > Réponse technique : mécanisme d'exécution JavaScript

Réponse technique : mécanisme d'exécution JavaScript

WBOY
Libérer: 2022-01-14 17:57:53
avant
1387 Les gens l'ont consulté

Cet article vous apporte quelques problèmes liés au mécanisme d'exécution en JavaScript. Qu'il s'agisse de travail ou d'un entretien, nous pouvons souvent rencontrer des scénarios où nous avons besoin de connaître l'ordre d'exécution du code. J'espère que cela sera utile à tout le monde.

Réponse technique : mécanisme d'exécution JavaScript

Processus et fils de discussion

Nous savons tous que le cœur de l'ordinateur est le processeur, qui entreprend toutes les tâches informatiques et que le système d'exploitation est le gestionnaire de l'ordinateur, qui est responsable de la tâche ; la planification, l'allocation et la gestion des ressources, régissant l'ensemble du matériel informatique ; les programmes d'application sont des programmes dotés de certaines fonctions et des programmes exécutés sur le système d'exploitation.

Process

Un processus est un processus d'exécution dynamique d'un programme avec des fonctions indépendantes sur un ensemble de données. Il s'agit d'une unité indépendante d'allocation et de planification des ressources par le système d'exploitation, et constitue le processus porteur pour l'application. en cours d'exécution. Il s'agit de la plus petite unité capable de posséder des ressources et de fonctionner de manière indépendante, et c'est également la plus petite unité pour l'exécution du programme.

Caractéristiques d'un processus :

  • Dynamique : Un processus est un processus d'exécution d'un programme. Il est temporaire, a un cycle de vie, est généré dynamiquement et meurt

  • Concurrence : tout processus peut être ; exécuté simultanément avec d'autres processus ;

  • Indépendance : le processus est une unité indépendante du système pour l'allocation des ressources et la planification ;

  • Structural : le processus se compose de trois parties : le programme, les données et le bloc de contrôle du processus.

Thread

Un thread est un processus de contrôle séquentiel unique dans l'exécution d'un programme. Il s'agit de la plus petite unité du flux d'exécution du programme et de l'unité de base de la planification et de la répartition du processeur. Un processus peut avoir un ou plusieurs threads, et chaque thread partage l'espace mémoire du programme (c'est-à-dire l'espace mémoire du processus). Un thread standard se compose d'un ID de thread, d'un pointeur d'instruction actuel (PC), de registres et d'une pile. Le processus se compose d'un espace mémoire (code, données, espace de processus, fichiers ouverts) et d'un ou plusieurs threads.

La différence entre le processus et le thread

  • Le thread est la plus petite unité d'exécution d'un programme, et le processus est la plus petite unité d'allocation de ressources par le système d'exploitation

  • Un processus se compose d'un ou plusieurs threads et d'un le thread est le code d'un processus Différentes routes d'exécution ;

  • Les processus sont indépendants les uns des autres, mais chaque thread sous le même processus partage l'espace mémoire du programme (y compris les segments de code, les ensembles de données, les tas, etc.) et certains processus -au niveau des ressources (telles que l'ouverture de fichiers et de signaux), les processus sont invisibles les uns aux autres ;

  • Planification et commutation : le changement de contexte de thread est beaucoup plus rapide que le changement de contexte de processus.

Pourquoi JS est-il monothread ?

JavaScript est utilisé comme langage de script de navigateur depuis sa naissance. Il est principalement utilisé pour gérer les interactions des utilisateurs et faire fonctionner le DOM. Cela détermine qu'il ne peut être qu'un seul thread, sinon cela entraînera des problèmes de synchronisation très complexes.

Par exemple : si JS est multithread, un thread veut modifier un élément DOM et un autre thread veut supprimer l'élément DOM, alors le navigateur ne sait pas qui écouter. Ainsi, afin d'éviter toute complexité, JavaScript a été conçu pour être monothread depuis sa naissance.

Afin de profiter de la puissance de calcul des CPU multicœurs, 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. . Par conséquent, cette nouvelle norme ne change pas la nature monothread de JavaScript

Principe du navigateur

En tant qu'ingénieur front-end, vous devez être familier avec les navigateurs, et les navigateurs sont multi-processus.

Composants du navigateur

  • Interface utilisateur : y compris barre d'adresse, avant/arrière/actualisation/signets

  • Moteur de navigateur : transfère les instructions entre l'interface utilisateur et le moteur de rendu

  • Moteur de rendu : utilisé pour dessiner le contenu demandé

  • Réseau : utilisé pour effectuer des appels réseau, tels que des requêtes http, il possède une interface indépendante de la plate-forme et peut fonctionner sur différentes plates-formes

  • Interpréteur JavaScript : utilisé pour analyser et exécuter du code JavaScript

  • Backend de l'interface utilisateur : utilisé pour dessiner des widgets de base, tels que des zones de liste déroulante et des fenêtres. La couche inférieure utilise l'interface utilisateur du système d'exploitation

  • Stockage des données : elle appartient à la couche de persistance et le navigateur enregistre. sur le disque dur Pour diverses données similaires aux cookies, HTML5 définit la technologie de base de données Web, qui est une technologie de stockage légère et complète côté client

Remarque : contrairement à la plupart des navigateurs, chaque navigateur de Google (Chrome) Chaque page d'onglet correspond à une instance de moteur de rendu. Chaque onglet est un processus indépendant

Quels processus le navigateur contient-il

Processus du navigateur

  • Le processus principal du navigateur (responsable de la coordination et du contrôle), il n'y a qu'un seul processus

  • Responsable de l'affichage de l'interface du navigateur et de l'interaction avec les utilisateurs. Tels que l'avant, l'arrière, etc.

  • Responsable de la gestion de chaque page, créant et détruisant d'autres processus

  • Dessinez le Bitmap (bitmap) dans la mémoire obtenue par le processus de rendu (Renderer) vers l'interface utilisateur

  • Gestion des ressources réseau, des téléchargements, etc. accélération matérielle (au plus une)

Processus de rendu

Responsable de l'analyse, de l'exécution et du rendu des documents de page

Quels threads sont inclus dans le processus de rendu

Fil de rendu GUI

Principalement responsable de analyse HTML, CSS, création d'une arborescence DOM, mise en page, dessin, etc.

Ce fil est lié au moteur JavaScript. Les threads s'excluent mutuellement Lorsque le thread du moteur JavaScript est exécuté, le thread de rendu de l'interface graphique sera suspendu lorsque la file d'attente des tâches. est inactif, le thread principal exécutera le rendu GUI

Le thread du moteur JavaScript est principalement responsable du traitement des scripts JavaScript et de l'exécution du code (comme le moteur V8)

Le navigateur ne peut avoir qu'un seul thread de moteur JS exécutant le JS programme en même temps, c'est-à-dire que JS est monothreadLe thread du moteur JS et le thread de rendu de l'interface graphique s'excluent mutuellement, donc le moteur JS bloquera le rendu des pages

Le thread de déclenchement chronométré

est responsable de exécuter la fonction timer (setTimeout, setInterval) Le compteur de timing du navigateur n'est pas compté par le moteur JS (car JS est monothread, s'il est bloqué, cela affectera la précision du compteur))

Temps et déclencheur timing via un thread séparé (une fois le timing terminé, ajoutez-le à la file d'attente des événements du thread de déclenchement d'événement et attendez l'exécution une fois le moteur JS inactif. Ce thread est le thread de déclenchement de timing, également appelé thread de minuterie

W3C). Il est stipulé dans la norme HTML que l'intervalle de temps inférieur à 4 ms dans setTimeout est compté pour 4 ms

Le thread de déclenchement de l'événement

est responsable de transmettre les événements préparés au thread du moteur JS pour exécution

Lorsque l'événement est déclenché , ce fil L'événement correspondant sera ajouté à la fin de la file d'attente à traiter, en attente du traitement du moteur JS

Fil de requête asynchrone

Après la connexion XMLHttpRequest, le navigateur ouvrira un fil

Lors de la détection de la requête changement de statut, s'il existe une fonction de rappel correspondante, le thread de requête asynchrone générera un événement de changement d'état et mettra la fonction de rappel correspondante dans la file d'attente pour attendre que le moteur JS s'exécute

Synchronisation et asynchrone

Étant donné que JavaScript est monothread, cela détermine que ses tâches ne peuvent pas être uniquement des tâches synchrones. Si les tâches qui prennent du temps sont également exécutées en tant que tâches synchrones, elles entraîneront un blocage de page. Par conséquent, les tâches JavaScript sont généralement divisées en deux catégories :

Tâches synchrones

Les tâches synchrones font référence à, Pour les tâches mises en file d'attente pour exécution sur le thread principal, la tâche suivante ne peut être exécutée qu'après l'exécution de la tâche précédente

Tâches asynchronesLes tâches asynchrones font référence à non ; en entrant dans le thread principal mais en entrant dans la tâche "file d'attente des tâches" (file d'attente des événements), ce n'est que lorsque la "file d'attente des tâches" informe le thread principal qu'une tâche asynchrone peut être exécutée que la tâche entrera dans le thread principal pour exécution.

Tâches asynchrones courantes : minuteries, ajax, liaison d'événements, fonctions de rappel, promesses, attente asynchrone, etc.

Les tâches synchrones et asynchrones entrent respectivement dans différents "lieux" d'exécution, entrant de manière synchrone dans le thread principal et entrant de manière asynchrone dans la table des événements et enregistrez la fonction.

Lorsque les éléments spécifiés dans le tableau des événements seront terminés, cette fonction sera déplacée vers la file d'attente des événements.

Une fois la tâche exécutée dans le thread principal, elle sera vide. Elle ira dans la file d'attente des événements pour lire la fonction correspondante et entrera dans le thread principal pour exécution.

    Le processus ci-dessus sera répété en continu, souvent appelé boucle d'événement.
  • Nous ne pouvons pas nous empêcher de nous demander : comment savons-nous que la pile d'exécution du thread principal est vide ? Il existe un processus de surveillance dans le moteur js, qui vérifiera en permanence si la pile d'exécution du thread principal est vide, une fois vide, elle ira dans la file d'attente des événements pour vérifier s'il y a une fonction en attente d'appel.
  • Macro-tâches et micro-tâches

  • En plus des tâches synchrones et des tâches asynchrones au sens large, JavaScript dispose également de définitions de tâches plus détaillées :

  • Macro-tâche : incluant le code global, setTimeout, setInterval

Micro-tâche : new Promise().then(callback) process.nextTick() Différents types de tâches entreront dans différentes files d'attente de tâches :

  • L'ordre de la boucle d'événements détermine le ordre d'exécution du code js. Après avoir saisi le code global (macro-tâche), le premier cycle démarre. Exécutez ensuite toutes les microtâches. Recommencez ensuite à partir de la macro-tâche, recherchez l'une des files d'attente de tâches à exécuter, puis exécutez toutes les micro-tâches.

  • Pile d'exécution et file d'attente des tâches

Pile d'exécution

Le code JavaScript est exécuté dans un contexte d'exécution. Il existe trois contextes d'exécution en JavaScript :

  • Contexte d'exécution global

  • Contexte d'exécution de fonction Lorsqu'une fonction JS est appelée, un contexte d'exécution de fonction sera créé

  • .

    contexte d'exécution eval, le contexte généré par la fonction eval (moins utilisé)

De manière générale, notre code JS a plus d'un contexte, alors quel est l'ordre d'exécution de ces contextes ?

Nous savons tous que la pile est une structure de données dernier entré, premier sorti. La pile d'exécution dans notre JavaScript est une telle structure de pile lorsque le moteur JS exécute le code, un contexte global est généré et inséré dans le code. pile d'exécution. Chaque fois qu'un appel de fonction est rencontré, le contexte d'exécution de la fonction est généré et poussé sur la pile d'exécution. Le moteur commence à exécuter la fonction depuis le haut de la pile et le contexte d'exécution apparaîtra après l'exécution.

function add(){
  console.log(1)
  foo()
  console.log(3)
}
function foo(){
  console.log(2)
}
add()
Copier après la connexion

Jetons un coup d'œil à la pile d'exécution du code ci-dessus :

Réponse technique : mécanisme dexécution JavaScript

File d'attente des tâches

Nous avons mentionné plus tôt que toutes les tâches en JavaScript sont divisées en tâches synchrones et tâches asynchrones, tâches synchrones, comme comme son nom l'indique, est une tâche qui est exécutée immédiatement. Elle entre généralement directement dans le thread principal pour être exécutée. Notre tâche asynchrone entre dans la file d'attente des tâches et attend que la tâche dans le thread principal soit exécutée avant de l'exécuter.

La file d'attente des tâches est une file d'attente d'événements, indiquant que les tâches asynchrones associées peuvent entrer dans la pile d'exécution. Le thread principal lit la file d'attente des tâches pour lire les événements qu'elle contient.

La file d'attente est une structure de données premier entré, premier sorti.

Nous avons mentionné ci-dessus que les tâches asynchrones peuvent être divisées en macro-tâches et micro-tâches, de sorte que les files d'attente de tâches peuvent également être divisées en files d'attente de macro-tâches et en files d'attente de micro-tâches

  • File d'attente de macrotâches : pour les travaux à relativement grande échelle, les plus courantes incluent setTimeout, setInterval, interaction utilisateur, rendu de l'interface utilisateur, etc. ;

  • File d'attente Microtask : effectuez des travaux plus petits, les plus courants incluent Promise, Process.nextTick

Event-Loop

Les tâches de synchronisation sont directement placés dans le thread principal pour exécution, et les tâches asynchrones (événements de clic, minuteries, ajax, etc.) sont exécutées en arrière-plan, en attendant que les événements d'E/S se terminent ou que les événements comportementaux soient déclenchés.

Le système exécute des tâches asynchrones en arrière-plan. Si un événement de tâche asynchrone (ou un événement comportemental est déclenché), la tâche sera ajoutée à la file d'attente des tâches et chaque tâche sera traitée par une fonction de rappel.

Les tâches asynchrones ici sont divisées en macro-tâches et micro-tâches. Les macro-tâches entrent dans la file d'attente des macro-tâches et les micro-tâches entrent dans la file d'attente des micro-tâches.

Les tâches de la file d'attente des tâches d'exécution sont spécifiquement complétées dans la pile d'exécution. Lorsque toutes les tâches du thread principal sont exécutées, lisez la file d'attente des micro-tâches, elles seront toutes exécutées, puis. lisez les tâches macro. File d'attente

Le processus ci-dessus sera répété en continu, ce que nous appelons souvent boucle d'événement (Event-Loop).

Réponse technique : mécanisme dexécution JavaScript

Exemple de vérification de question

Regardons une question à vérifier

(async ()=>{
    console.log(1) 
  
    setTimeout(() => {
    console.log('setTimeout1')
    }, 0);
  
    function foo (){
        return new Promise((res,rej) => {
            console.log(2)
            res(3)
        })
    }
  
    new Promise((resolve,reject)=>{
    console.log(4)
    resolve() 
    console.log(5)
    }).then(()=> {
    console.log('6')
    })
  
    const res = await foo();
    console.log(res);
    console.log('7')
  
    setTimeout(_ => console.log('setTimeout2'))
})()
Copier après la connexion

L'ordre d'impression est : 1,4,5,2,6,3,7,setTimeout1,setTimeout2

Analyse :

Le code commence par le haut Exécutez ensuite, rencontrez d'abord console.log(1), imprimez 1 directement, puis rencontrez un minuteur qui appartient à une tâche macro, placez-le dans la file d'attente des tâches macro

Ensuite, rencontrez une promesse, car la nouvelle promesse est une tâche synchrone, alors imprimez 4 directement, lorsque vous rencontrez solve, qui est la fonction then suivante, placez-la dans la file d'attente des microtâches, imprimez 5

, puis exécutez wait foo. Il y a une promesse dans la fonction foo, et une nouvelle promesse est. une tâche synchrone, donc elle en imprimera 2 directement, et wait return est un rappel de promesse, la tâche après wait est placée dans la file d'attente des microtâches

Enfin, un minuteur est rencontré et placé dans la file d'attente des macrotâches

La tâche de la pile d'exécution est terminée , allez d'abord dans la file d'attente des microtâches pour obtenir l'exécution de la microtâche, exécutez-la d'abord. Pour la première microtâche, imprimez 6, puis exécutez la deuxième microtâche, imprimez 3, 7

Une fois la microtâche exécutée, allez dans la file d'attente des macrotâches pour obtenir le exécution de macrotâches, impression setTimeout1, setTimeout2

[Recommandations associées : Tutoriel d'étude 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!

Étiquettes associées:
source:juejin.im
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal