Appuyez sur Entrée pour voir vos résultats ou Echap pour annuler.

La boucle d’événements de JavaScript

Parce que c’est un langage puissant avec des paradigmes différents des langages dits backend, JavaScript semble faire peur à beaucoup de développeurs. On arrive à un point où les frameworks frontend nous submergent dans leur simplicité, mais on oublie trop souvent qu’il y a des bases importantes dans le langage. Aujourd’hui, je vous présente le fonctionnement de la boucle d’événements de JavaScript.

Que c’est?!

Vous le savez peut-être, mais la principale différence entre JS et un autre langage comme C# ou Java vient du fait qu’il exécute les opérations d’entrée/sortie de façon asynchrone, donc non-bloquantes. Je m’explique…

Évidemment, tout ceux et celles qui ont déjà utilisé au moins jQuery savent que le résultat est « 1 3 2 », même si, logiquement, dans le code, ça devrait être « 1 2 3 ». Du moins, tout dev débutant en JS l’espère profondément 😀

Mais là n’est pas le but de cet article. Je veux pousser le concept plus loin pour bien comprendre le fonctionnement de JS. Quand, comment et dans quel ordre ça arrive?

Les événements

En soi, tous les événements qui arrivent dans la page web s’ajoutent sur la pile d’événements, comme par exemple : si vous cliquez, tapez sur une touche, survolez un lien, faites un appel Ajax, etc. Par contre, il faut comprendre que le navigateur (ou Node) doit aussi faire autre chose qu’exécuter votre code JS comme : rendre le DOM, le CSSDOM ou peindre le résultat à l’écran.

Il doit donc jongler avec les événements tout en assurant que la vue sera bien peinte assez fréquemment pour avoir une belle fluidité (sauf pour IE, lolz).

La boucle

Une des meilleures vulgarisation que j’ai vue (en plus d’être très drôle) est celle Jake Archibald, un développeur de Google Chrome. J’essaierai de lui arriver à la cheville, mais allez écouter sa vidéo sur YouTube!

Une boucle infinie roule en permanence. Séparons les tâches à exécuter par cette boucle en deux : Votre code, le code du navigateur (générer le DOM, etc.)

Je t’entends juger mes talents avec Paint, mais focus! La théorie est là! Le cercle central représente la boucle infinie. Tant qu’il n’y a pas de code JS à rouler, la porte A reste fermée, et tant que le navigateur n’a rien à redessiner à l’écran, la porte B reste fermée. Le navigateur tourne en boucle.

Lorsque vous cliquez sur un bouton, votre code est alors mis sur la pile d’événements, puis la porte A s’ouvre permettant au thread d’exécuter votre code, puis de revenir dans la boucle d’événements. Pour afficher l’animation du bouton qui « renfonce », la porte B s’ouvre, l’animation joue, puis la porte se referme.

Vous avez sûrement compris : la boucle alterne entre votre code et celui du navigateur.

Le contrôle

C’est donc pour cette raison que l’affichage « gèle » si vous avez du code qui prend trop de temps à exécuter (une grosse boucle par exemple). Par contre, c’est possible d’avoir un certain contrôle sur l’exécution. On n’a qu’à penser aux Promises ou à setTimeout().

Cas 1 – Delayer avec setTimeout()

Comme son nom l’indique, cette fonction sert à exécuter un bout de code après un certain laps de temps qui se calcule en millisecondes.

Supposons le code suivant :

Si vous incluez ce script dans une page HTML avec un bouton qui logue « Bonjour » au clic, vous serez toujours en mesure d’exécuter le handler du clic, puisque le navigateur exécute la boucle d’événements au complet entre chaque pop de la pile d’événements. Une valeur de 0 milliseconde signifie que JS va l’exécuter immédiatement après la porte A (vers votre code) et avant la porte B (vers le code d’affichage).

Votre code n’est pas bloqué.

Cas 2 – Delayer avec Promise.resolve().then()

Au contraire, une « Promise » s’exécute à l’intérieur même de la boucle, après la porte A, mais avant de ressortir de la boucle de votre code. Prenons cet exemple :

*Chlang* votre navigateur est gelé.

Voici dernier exemple qui démontre bien la différence entre les deux méthodes. Un morceau de robot pour celui qui devine l’ordre d’exécution 😀

Réponse : 1 4 3 2!

1 et 4 sont assez évidents, puisque vous êtes maintenant un expert de l’event loop, vous avez compris que le code délaye setTimeout() et Promise.resolve().then(). Mais pourquoi 3 avant 2?

Une image vaut mille mots :

1 et 4 : Au début de la boucle exécutant votre code.

3 : À la fin de la boucle exécutant votre code.

2 : Juste avant d’entre dans la boucle de dessin du navigateur.

Conclusion

Aujourd’hui, vous avez appris comment fonctionne la boucle d’événements de JavaScript et comment elle se comporte dans l’exécution des méthodes délayées, soit avec une Promise, soit avec setTimeout(). Maintenant, allez voir la vidéo de Jake sur YouTube et dites-moi ce que vous en pensez dans les commentaires ci-dessous 🙂

Bon code!

Suivez-nous par courriel!

Saisissez votre adresse courriel pour vous abonner au blog d'Ezo et recevoir une notification de chaque nouvel article par email.