‫Instructeur : Bon retour.
‫Apprenons maintenant tout sur la boucle d'événement, qui
‫est le cœur du Node. architecture js.
‫Et c'est probablement la conférence la
‫plus importante de cette section, alors assurez-vous de bien
‫comprendre tout ce que je vous montre pendant cette vidéo.
‫Alors, commençons.
‫Donc, voici un schéma similaire à la dernière conférence
‫afin que nous sachions exactement de quoi nous parlons ici.
‫Donc, nous sommes toujours dans un processus Node dans le thread
‫unique où s'exécute la boucle d'événement, d'accord ?
‫Maintenant, la première chose que vous
‫devez savoir est que la boucle d'événement est
‫l'endroit où tout le code
‫d'application qui se trouve à l'intérieur des fonctions de rappel est exécuté.
‫Donc, fondamentalement, tout le code qui n'est pas du code de niveau supérieur
‫s'exécutera dans la boucle d'événements.
‫Certaines parties peuvent être déchargées vers le pool de threads comme
‫nous l'avons vu dans la
‫dernière conférence, mais c'est la boucle d'événements qui s'occupe de tout cela.
‫Comme je l'ai déjà dit, c'est vraiment le
‫cœur de l'architecture Node.
‫Bon, maintenant, comme je l'ai mentionné plusieurs fois dans la première
‫partie du cours, Node. js est entièrement construit
‫autour de fonctions de rappel.
‫Donc, des fonctions qui sont
‫appelées dès qu'un travail est terminé dans le futur.
‫Vous vous en souvenez ?
‫Et cela fonctionne de cette façon parce
‫que Node utilise une architecture déclenchée par
‫des événements, ce dont nous allons parler dans
‫l'une des prochaines vidéos.
‫Mais ce que vous devez savoir
‫pour l'instant, c'est que des
‫choses comme notre application recevant une requête HTTP sur notre serveur ou un timer
‫expirant ou un fichier se terminant à lire, tout cela émettra
‫des événements dès qu'ils auront terminé leur
‫travail, et notre événement loop va alors récupérer
‫ces événements et appeler
‫les fonctions de rappel associées à chaque événement.
‫D'accord, ça a du sens ?
‫Donc, encore une fois, la boucle d'événements reçoit des événements chaque
‫fois que quelque chose d'important se produit,
‫et appellera ensuite les rappels nécessaires tels que nous
‫les définissons dans notre code.
‫Donc, en résumé, on dit généralement
‫que la boucle d'événements effectue l'orchestration, ce qui
‫signifie simplement qu'elle reçoit des événements, appelle
‫leurs fonctions de rappel et
‫décharge les tâches les plus coûteuses vers le pool de threads.
‫Maintenant, comment tout cela fonctionne-t-il réellement dans les coulisses ?
‫Dans quel ordre ces rappels sont-ils exécutés ?
‫Eh bien, c'est ce que nous allons découvrir ensuite.
‫Alors, rappelez-vous, lorsque nous démarrons notre application Node,
‫la boucle d'événements commence immédiatement à s'exécuter.
‫Maintenant, la boucle d'événements a plusieurs phases,
‫et chaque phase a une file d'attente de
‫rappels, qui sont les rappels provenant des événements
‫que la boucle d'événements
‫reçoit, comme nous en avons parlé dans la dernière diapositive.
‫Maintenant, à certains endroits, vous lirez
‫qu'il n'y a qu'une seule file d'attente de rappel ou une seule file d'attente
‫d'événements, mais en fait, comme je l'ai dit, la boucle d'événements comporte de nombreuses
‫phases où chaque phase a sa propre file d'attente de rappel.
‫Voyons maintenant les quatre phases les plus importantes.
‫Il y a une ou deux autres phases
‫qui sont utilisées en interne par Node,
‫mais celles-ci ne sont pas
‫si importantes et je ne vais pas en parler.
‫Ainsi, la première phase
‫prend en charge les rappels des minuteurs
‫expirés, par exemple, à partir de la fonction setTimeout().
‫Ainsi, s'il y a des fonctions de rappel
‫des temporisateurs qui viennent d'expirer, ce sont les premières
‫à être traitées par la boucle d'événement.
‫Si un temporisateur expire plus tard pendant le temps où
‫l'une des autres phases est en
‫cours de traitement, eh bien, le rappel de ce temporisateur ne sera
‫appelé que dès que la boucle d'événement reviendra à cette première phase.
‫Avoir du sens ?
‫Et cela fonctionne comme ça dans les quatre phases.
‫Ainsi, les rappels dans chaque file d'attente sont traités
‫un par un jusqu'à ce qu'il n'y ait plus personne dans la
‫file d'attente, et alors seulement, la boucle d'événements entrera dans la phase suivante.
‫Ensuite, nous avons l'interrogation d'E/S et l'exécution de rappels d'E/S.
‫Et encore une fois, n'oubliez pas que I/O signifie entrée/sortie.
‫Ainsi, l'interrogation signifie essentiellement rechercher de nouveaux événements d'E/S
‫prêts à être traités et
‫les mettre dans la file d'attente de rappel.
‫Et rappelez-vous que dans le contexte d'une application Node, les
‫E/S signifient principalement des choses comme la mise en réseau et l'accès aux fichiers, et
‫donc, c'est dans cette phase où probablement 99% de notre code
‫est exécuté, simplement parce que
‫dans une application Node typique, la majeure
‫partie de ce que nous devons faire est lié à la mise
‫en réseau et également à l'accès aux fichiers.
‫La phase suivante concerne les rappels setImmediate, et setImmediate est
‫un type spécial de minuteur que nous
‫pouvons utiliser si nous voulons traiter les rappels immédiatement après la
‫phase d'interrogation et d'exécution des E/S, ce qui peut
‫être important dans certains cas d'utilisation plus avancés.
‫D'accord.
‫Et enfin, la quatrième phase concerne les rappels rapprochés, qui, encore une fois,
‫ne sont pas si importants pour nous,
‫mais je le mets quand même ici par souci d'exhaustivité.
‫Fondamentalement, dans cette phase, tous les événements de fermeture sont
‫traités, par exemple, lors de la fermeture d'un serveur Web ou d'un WebSocket.
‫Ce sont donc les quatre phases de la boucle d'événement,
‫mais en plus de ces quatre files d'attente de rappel que nous
‫venons de voir, il existe en fait également
‫deux autres files d'attente, la file d'attente nextTick() et l'autre file
‫d'attente de microtâches, qui est principalement destinée aux promesses résolues.
‫Si vous n'êtes pas familier avec
‫les promesses, nous en parlerons un peu dans une section ultérieure.
‫Quoi qu'il en soit, s'il y a des
‫rappels dans l'une de ces deux files
‫d'attente à traiter, ils seront exécutés juste après la fin de
‫la phase actuelle de la boucle d'événements au lieu
‫d'attendre que la boucle entière se termine.
‫D'accord?
‫Donc, en d'autres termes, après chacune de ces quatre
‫phases, s'il y a des rappels dans ces deux files
‫d'attente spéciales, ils seront exécutés immédiatement.
‫Maintenant, par exemple, imaginez qu'une promesse résout et
‫renvoie des données d'un appel d'API pendant que le rappel
‫d'un temporisateur expiré est en cours d'exécution.
‫Ainsi, dans ce cas, le rappel de promesse sera exécuté
‫juste après la fin de celui du minuteur.
‫D'accord?
‫Et la même logique s'applique également à la file d'attente nextTick(),
‫dont nous n'avons pas encore parlé.
‫Donc, fondamentalement, traiter le nextTick () est une fonction que nous
‫pouvons utiliser lorsque nous avons vraiment, vraiment besoin
‫d'exécuter un certain rappel juste
‫après la phase de boucle d'événement en cours.
‫C'est un peu similaire à setImmediate, à
‫la différence que setImmediate ne s'exécute qu'après la
‫phase de rappel d'E/S.
‫Ce qui est similaire,
‫cependant, c'est que les deux sont destinés à des cas d'utilisation vraiment avancés,
‫et nous n'aurons probablement même pas besoin d'eux
‫tout au long de ce cours.
‫Mais de toute façon, je voulais également inclure ces éléments plus
‫complexes ici afin que vous ayez les outils
‫dont vous avez besoin si vous avez vraiment
‫besoin de creuser profondément dans Node. js si tu veux.
‫Très bien, et avec cela, nous avons en fait terminé
‫un tick de la boucle d'événements, et un tick n'est fondamentalement qu'un cycle
‫dans cette boucle.
‫Il est donc maintenant temps de décider si la boucle
‫doit continuer jusqu'au prochain tick ou si le programme doit se terminer.
‫Et comment Node fait-il cela ?
‫Eh bien, c'est très simple.
‫Node vérifie simplement s'il y a des
‫temporisateurs ou des tâches d'E/S qui s'exécutent toujours en
‫arrière-plan, et s'il n'y en a pas, il quittera l'application.
‫Mais s'il y a des temporisateurs ou des tâches d'E/S en
‫attente, eh bien, il continuera à exécuter
‫la boucle d'événements et passera directement au tick suivant.
‫Ainsi, par exemple, lorsque
‫nous écoutons les requêtes HTTP entrantes comme nous
‫l'avons fait dans notre projet de batterie de nœuds dans
‫une section précédente, nous exécutions essentiellement une tâche d'E/S,
‫et c'est pourquoi la boucle d'événement,
‫et donc, Node. js, continuez
‫à exécuter et continuez à écouter les nouvelles requêtes
‫HTTP entrant au lieu de simplement quitter l'application.
‫De plus, lorsque nous écrivons ou lisons un
‫fichier en arrière-plan, il s'agit également d'une tâche d'E/S, et
‫il est donc logique que l'application ne se ferme
‫pas pendant qu'elle travaille avec ce fichier, n'est-ce pas ?
‫D'accord, et c'est essentiellement ce que vous devez savoir
‫sur le Node. boucle d'événement js.
‫Si vous avez besoin de plus de détails que
‫cela, eh bien, vous
‫pouvez toujours essayer de lire la documentation officielle de Node, qui devrait
‫être assez facile à comprendre à ce stade
‫maintenant que vous comprenez déjà la plupart de la boucle d'événements de toute façon.
‫Et je veux juste souligner qu'il
‫est vraiment très important que vous compreniez correctement la boucle
‫d'événements afin que vous puissiez écrire votre
‫propre code performant et également déboguer votre propre code lorsque
‫quelque chose ne va pas de manière inattendue.
‫Et maintenant, juste pour finir, passons en revue certaines
‫des choses dont nous avons parlé ici.
‫Donc, en un mot, la chose la plus importante que je
‫veux que vous compreniez de cette conférence, et
‫peut-être de tout ce cours, est que la
‫boucle d'événements est ce qui rend la
‫programmation asynchrone possible dans Node. js, ce qui en fait
‫la fonctionnalité la plus importante dans la conception de Node et la
‫création de Node. js complètement
‫différent des autres plateformes.
‫Il prend en charge tous les événements
‫entrants et effectue l'orchestration en déchargeant les tâches les plus lourdes dans
‫le pool de threads et en effectuant lui-même le travail le plus simple.
‫N'oubliez pas non plus que nous avons besoin de
‫la boucle d'événement car dans Node. js tout fonctionne dans un
‫seul thread, et ainsi, vous pouvez avoir
‫des milliers ou des millions d'utilisateurs accédant au même thread en même temps.
‫Cela rend Node si léger et évolutif,
‫mais en même temps, cela présente le danger
‫de bloquer notre
‫thread unique, ce qui ralentirait l'ensemble
‫de l'application ou même s'arrêterait pour tous vos utilisateurs accédant à l'application, n'est-ce pas ?
‫Désormais, dans d'autres langages comme PHP exécutés sur
‫un serveur Apache, en gros, un nouveau thread est créé
‫pour chaque nouvel utilisateur, ce qui est beaucoup plus gourmand en ressources.
‫Mais d'un autre côté, il n'y a
‫aucun danger de blocage, non ?
‫Donc, tout ce modèle facilite un peu
‫l'utilisation de PHP pour les débutants, mais bien sûr, il
‫a ses propres inconvénients, sur lesquels
‫je ne vais pas m'attarder à ce stade.
‫Quoi qu'il en soit, permettez-moi
‫de vous rappeler à nouveau qu'il est de votre responsabilité de ne pas bloquer
‫la boucle d'événement, et voici donc quelques directives à ce sujet.
‫Tout d'abord, n'utilisez pas les versions
‫de synchronisation des fonctions des modules fs,
‫crypto ou zlib dans vos fonctions de rappel, d'accord ?
‫Ainsi, dans notre premier projet, nous avons en fait
‫utilisé la version synchrone, mais c'était dans le code de niveau
‫supérieur, donc en dehors de tout rappel.
‫Et puisque ce code s'exécute avant même que la boucle d'événement ne
‫commence, eh bien, ce n'est pas un problème d'utiliser la version synchrone là-bas.
‫De plus, et c'est probablement assez évident,
‫n'effectuez pas de calculs très complexes dans la boucle d'événements.
‫Donc, des trucs comme croquer
‫des millions de nombres dans des boucles à l'intérieur de boucles, ou quelque chose comme ça.
‫Ensuite, soyez prudent avec JSON dans des objets très volumineux car à
‫un moment donné, l'analyse ou la chaîne de
‫caractères JSON peut commencer à prendre beaucoup de temps.
‫Et enfin, n'utilisez pas d'expressions régulières trop complexes, par exemple,
‫avec plusieurs quantificateurs imbriqués ou références arrière,
‫car encore une fois, elles
‫peuvent prendre plus de temps que prévu.
‫Ce ne sont, bien sûr, que quelques
‫directives de haut niveau, mais elles vous permettront de démarrer sur
‫la bonne voie.
‫Maintenant, il existe des solutions
‫potentielles à ces problèmes de blocage, comme le déchargement manuel
‫vers le pool de threads ou l'utilisation de processus enfants, et
‫nous pourrions en parler d'ici la fin
‫du cours ou dans le futur, mais
‫pour l'instant, il est important que vous comprenez et suivez ce
‫conseil de vraiment ne pas bloquer la boucle d'événement.
‫D'accord.
‫Ensuite, je vais vous donner un petit exemple pour vous montrer
‫certaines des choses dont
‫nous avons parlé dans la pratique.