Callback queue & Event loop JavaScript - JS - Sous Le Capot - Partie 3

Explication du fonctionnement de Callback queue & Event loop en Javascript.
Arthur.jpg
Arthur COMBE, JavaScript loverMis à jour le 10 Août 2020
AXOPEN_Blog_JavaScript_CallBack_EventLoop.jpg

On se retrouve aujourd’hui pour le 3ème article de notre série : Javascript sous le capot ! Focus sur Callback queue & Event loop - Javascript. Allez, c’est parti !

3- Callback queue & Event loop - Javascript

Le Javascript étant un langage single-thread dans un univers du Web où la réactivité est importante, les APIs WEB ont pensé à une solution afin d’ajouter une composante asynchrone au langage : callback queue et event loop.

Une nouvelle stack ?

Comme on l’a vu dans notre précédent article, Javascript ne contient qu’une seule stack d’exécution (pile d’exécution JS), ce qui l’empêche d’effectuer plusieurs actions simultanément.

Pour être plus précis, le moteur de Javascript ne peut pas effectuer plusieurs actions en même temps, mais les APIs WEB le peuvent. On peut donc les imaginer comme des threads à part entière.

Seulement, les APIs WEB ne peuvent pas modifier l’ordre d’exécution du code en ajoutant des éléments dans la stack. C’est pour cela que callback queue et event loop ont été créées.

Il s’agit d’une sorte de « file d’attente », qui permet d’effectuer des traitements sans bloquer la pile d’exécution JS, et donc, le bon fonctionnement de votre application, et surtout l’UIL'UI signifie "user interface", et se compose de tous les éléments graphique d'une interface utilisateur..

Le rôle de event loop est tout simple : déplacer les éléments de la callback queue dans la pile d’exécution JS lorsque cette dernière est vide.

Asynchrone

Grâce à ces nouveaux éléments, nous avons accès à des composants asynchrones dans Javascript.

Nous avons donc maintenant :

  • Pile d’exécution JS : contient les données du déroulement de votre programme.
  • APIs WEB : de nouvelles fonctionnalités, pouvant être considérées comme des threads à part entière.
  • Callback queue : nouvelle file où vont être stockés les résultats d’exécutions aux APIs WEB.
  • Event loop : s’occupe de déplacer les éléments de la callback queue dans la pile d’exécution JS lorsque cette dernière est vide.

Voici une petite animation pour illustrer tout le mécanisme sur un programme simple : 

callback-queue-event-loop-javascript-asynchrone.gif

On voit donc bien le Hi qui s’affiche dans la console, puis le setTimeout qui se met dans la stack pour disparaître immédiatement après (son seul but était de lancer la fonction, c’est les APIs WEB qui se chargent d’attendre les 5000ms).
Pour finir, le JSConfEU s’affiche dans la console.

Une fois les 5 secondes terminées, le setTimeout arrive à son terme, il met dans la fonction cb() dans la callback queue (task queue ici). Event loop voit que la stack (pile d’execution JS) est vide, il push donc cb() dans celle-ci, ce qui va afficher there dans la console.

Performances Javascript

Même si grâce à cette nouvelle file (callback queue), on peut avoir des appels asynchrones qui prennent du temps, sans avoir à se soucier de bloquer la stack, et donc l’UI. Mais, il faut tout de même faire attention !
En effet, au même titre que la pile d’exécution JS, il n’existe qu’une seule callback queue. Énormément d’appels peuvent délayer tous vos autres traitements asynchrones, ce qui peut donner un effet de ralentissement.

Cela peut notamment arriver avec une utilisation excessive d’événements Javascript.
Un trop grand nombre d’inscriptions à des événements peut remplir la callback queue très rapidement, et donc délayer des appels plus importants.

Une autre animation pour illustrer ce propos : 

callback-queue-event-loop-javascript-performances.gif

Nous avons ici souscrit à 2 événements différents : scroll et click.
Lorsque nous faisons défiler la page, l’événement scroll est déclenché, chaque rafraîchissement de la page (60 fois par seconde), ce qui remplit très vite la callback queue. Quand on clique sur le bouton, on voit donc que les événements sont déclenchés et mis à la fin de la file.

Cet exemple est fait pour illustrer le propos, et n’est bien évidemment pas à vitesse réelle.
Mais, on voit bien que si on ne fait pas attention, il est facile de créer des ralentissements dans vos applications, même en asynchrone.

À vous !

Nous allons terminer sur un petit exercice très connu dans le milieu du JS, et que vous devriez trouver simple si vous avez tout compris jusqu’à maintenant !

Prenons le programme suivant :

console.log(’hi’);

setTimeout(function cb(){
    console.log(’there’)
}, 0);

console.log(’JSConfEU’);

Quel sera l’affichage dans la console ? Sachant que le 0 correspond au temps d’attente avant le callback cb(), ici il n’y a donc aucun temps d’attente.

......

.....

....

...

..

.

Sans plus tarder voici la réponse : 

callback-queue-event-loop-javascript-exercice.png

Comme expliqué plus haut, même si le setTimeout se termine immédiatement, event loop doit attendre que la stack soit vide avant de pouvoir y mettre les éléments de callback queue. there sera donc affiché en dernier, même s’il termine avant le console.log(’JSConfEU’).

Merci à Philip Roberts et sa conférence sur JSConf pour les designs, ainsi que le site loupe, qui permet de visualiser différents mécanismes du JS.

Callback queue & Event loop JS - Pour aller plus loin

Pour aller plus loin dans la compréhension de Javascript, voici quelques liens utiles :