JavaScript sous le capot : boucle d'événement
Maîtrisons JavaScript en explorant son fonctionnement à partir de zéro

Avez-vous déjà rencontré des erreurs indéfinies ou eu du mal à identifier la portée d'une variable ?
C'est vraiment long de déboguer toute erreur sans savoir comment le code fonctionnait.
Dans ce blog, je vais vous montrer comment des concepts avancés tels event loop
que execution context
, call stack
et callback queue
fonctionnent réellement.
Un avertissement — Les concepts sont incroyablement riches en connaissances et interconnectés, alors ne clignez même pas des yeux !
Moteur JavaScript
Le moteur V8 de Google est une illustration bien connue d'un moteur JavaScript. Par exemple, Chrome et Node.js utilisent tous deux le moteur V8. Fondamentalement, le moteur V8 se compose de deux parties -
- Call Stack : Tout le code est exécuté à l'intérieur. Cela fonctionne comme la structure de données Stack, c'est-à-dire en suivant le concept LIFO (Last In First Out).
- Tas de mémoire : où l'allocation de mémoire se produit. Contrairement à la structure de données en tas, ce n'est qu'une mémoire.

Le contexte d'exécution global ou GEC est le contexte d'exécution par défaut créé par le moteur JavaScript chaque fois qu'un fichier de script est reçu.
Tout le code JavaScript qui n'est pas à l'intérieur d'une fonction est exécuté dans GEC
. Les étapes suivantes sont effectuées dans GEC
—
- Construire un espace mémoire pour stocker toutes les variables et fonctions à l'échelle mondiale
- Générer un objet global.
- Générer le mot-clé
this

En fonction de l'endroit où votre code sera exécuté, cela déterminera où this
se trouve. Par exemple, dans Node.js, il pointe vers un objet global distinct, alors que dans le navigateur, il pointe vers l' window
objet.

Pile d'appels (ou pile d'exécution de fonctions)
JavaScript est single-threaded
, comme vous l'avez déjà entendu. Mais qu'est-ce que cela signifie réellement ?
Cela signifie qu'un moteur JavaScript ne contient qu'un call stack
ou function execution stack
.
- Comme nous le savons, chaque fois que le compilateur explore votre code pour la première fois, le moteur JS est invité à créer un
Global Execution Context
ouGEC
par le compilateur ainsi qu'à le placer dans le fichierCall Stack
. - Votre code entier est exécuté un par un dans le
Global Execution Context
et il alloue de la mémoire pour la définition de fonction ou la déclaration de variable et l'y stocke. - Mais lorsqu'un appel de fonction est trouvé, un
Functional Execution Context
orFEC
est créé pour exécuter le code de la fonction, puis il est ajouté en haut ducall stack
. - L'interpréteur supprime une fonction de
call stack
chaque fois que la fonction se termine. Une fonction se termine - lorsqu'elle atteint la fin de sa portée ou une instruction de retour. - Enfin, l'exécution de tout votre code
GEC
est supprimée du fichierCall Stack
.
Ne vous inquiétez pas, démontrons-le avec un exemple.
function f1{
console.log('f1');
}
f1();
console.log('end');

Étape 2 : — Dans notre exemple, la 1ère ligne sera exécutée, c'est-à-dire f1
. Une mémoire sera allouée f1
et stockée pour sa définition.

Étape 3 : — Dans la 2e ligne, une fonction est appelée. Pour cet appel de fonction, un Function Execution Context
ou FEC
sera créé et sera stocké au-dessus du fichier Call Stack
.

Étape 4 : — Maintenant, tout f1()
sera exécuté ligne par ligne et après avoir terminé l'exécution, il sera supprimé du fichier Call Stack
.

Étape 5 : — Ensuite, la dernière ligne console.log('end')
sera exécutée et imprimera 'end' sur la console. Enfin, l'exécution de tout votre code Global Execution Context
sera supprimée du fichier Call Stack
.

Comment JS gère-t-il les tâches asynchrones ?
JavaScript, comme nous sommes tous connus, est un langage synchrone à thread unique (une tâche à la fois), et le thread unique qui call stack
exécute immédiatement tout ce qui se trouve à l'intérieur.
Mais que se passe-t-il si nous devons exécuter quelque chose après 5 secondes ? Pouvons-nous mettre cela à l'intérieur du call stack
?
Non, nous ne pouvons pas. Parce call stack
qu'il n'y a pas de minuterie. Mais comment pouvons-nous faire cela?
C'est là qu'intervient le runtime JavaScript .

Cela peut être navré si je vous dis maintenant - setTimeout()
ne fait pas partie de JavaScript, même si console.log()
les événements DOM font tous partie des API Web qui donnent accès à JavaScript Engine pour utiliser toutes ses propriétés dans Global Execution Context (GEC) via l'objet global window
. Ces API Web sont appelées asynchrones .
Qu'est-ce que la file d'attente de rappel ?
Une file d'attente de tâches appelée « file d'attente de rappel » ou « file d'attente de tâches » est une file d'attente qui est exécutée une fois que les tâches en cours de la pile d'appels sont terminées. Les tâches enregistrées dans l'API Web sont déplacées de l'API Web vers la file d'attente de rappel.
La file d'attente de rappel fonctionne comme une structure de données de file d'attente, ce qui signifie que les tâches sont gérées dans l'ordre FIFO (premier entré, premier sorti), par opposition à une pile d'appels, ce qui signifie que les tâches sont gérées dans l'ordre dans lequel elles ont été ajoutées à la file d'attente.

Qu'est-ce que la boucle d'événement ?
Une boucle d'événements JavaScript ajoute une tâche de la file d'attente de rappel à la pile des appels dans l'ordre FIFO dès que la pile des appels est vide.
La boucle d'événements est bloquée si la pile d'appels exécute actuellement du code et n'ajoutera pas d'appels supplémentaires à partir de la file d'attente tant que la pile ne sera pas à nouveau vide. Cela est dû au fait que le code JavaScript est exécuté de manière exécutée jusqu'à la fin.
Comprenons les concepts ci-dessus avec un exemple.
- Au début,
Global Execution Context
est créé pour notre code à l'intérieur de notrecall stack
etGEC
exécute notre code ligne par ligne. GEC
exécute la 1ère ligne et imprime 'Start' sur notre console.- En exécutant la 2ème ligne,
setTimeout()
l'API Web sera appelée etsetTimeout()
donnera ensuite accès à la fonction de minuterie. Ensuite, vous pourrez définir5000ms
un temps de retard. - Lorsque vous transmettez la
callBack()
fonction via lesetTimeout()
, lecallBack()
sera enregistré en tant que rappel sur l'API Web Web. - Et puis
GEC
exécute la 1ère ligne et imprime 'End' sur la console. - Lorsque tout le code est exécuté,
GEC
sera supprimé de notre fichiercall stack
. - Après
5000 millisecond
, lacallBack()
fonction qui est enregistrée dans leweb API
, est déplacée à l'intérieur ducall Back Queue
. Event loop
met lacallBack()
fonction dans lecall Stack
quand c'est fait c'est tout le travail. Et enfin, lacallBack()
fonction est exécutée et imprime 'Call Back' dans la console.








function f1() {
console.log('f1');
}
function f2() {
console.log('f2');
}
function main() {
console.log('main');
setTimeout(f1, 0);
f2();
}
main();
Si vous pensez que "f1" sera imprimé avant "f2", alors vous vous trompez. Ce sera -
main
f2
f1
Le mécanisme discuté de JavaScript convient à toute fonction de rappel ou requête API.
Observons étape par étape comment le deuxième exemple fonctionne dans l'environnement d'exécution.

- Au début
GEC
sera créé à l'intérieur ducall stack
puis le code sera exécuté ligne par ligne dansGEC
. Il stocke toutes les définitions de fonctions dans le tas de mémoire . - Lorsque le
main()
est appelé, unFunction Execution Context (FEC)
est créé, puis il entre dans la pile des appels. Après cela, tout le code de lamain()
fonction sera exécuté ligne par ligne. - Il a un journal de console pour imprimer le mot main. Ainsi, le
console.log('main')
s'exécute et sort de la pile. - L'
setTimeout()
API du navigateur prend place. La fonction de rappel le place dans la file d'attente de rappel. Mais dans la pile, l'exécution se produit comme d'habitude, doncf2()
entre dans la pile. Le journal de la console desf2()
exécutions. Les deux sortent de la pile. - Et puis le
main()
sort également de la pile. - La boucle d'événements reconnaît que la pile d'appels est vide et qu'il existe une fonction de rappel dans la file d'attente. Ainsi, la fonction de rappel
f1()
sera placée dans la pile par leevent loop
. L'exécution commence. Le journal de la console s'exécute etf1()
sort également de la pile. Et enfin, rien d'autre n'est dans la pile et la file d'attente pour s'exécuter davantage.
C'est ma pratique et ma note. Si vous l'avez trouvé utile, veuillez montrer votre soutien en cliquant sur l'icône clap ci-dessous. Vous pouvez me suivre sur medium .