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 !
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.
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.
Grâce à ces nouveaux éléments, nous avons accès à des composants asynchrones dans Javascript.
Nous avons donc maintenant :
Voici une petite animation pour illustrer tout le mécanisme sur un programme simple :
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.
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 :
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.
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 :
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.
Pour aller plus loin dans la compréhension de Javascript, voici quelques liens utiles :
Explication du fonctionnement du moteur JavaScript : moteur, WebAPIs, Call Stalk, Simultanéité.
Tuto - Talend – Appeler et exposer un web service rest
Qui n’a jamais eu le besoin de comparer 2 schemas de base de données Mysql après avoir oublier de noter l’ensemble des modifications apportées à un environnement ?