IdentifiantMot de passe
Loading...
Mot de passe oubli� ?Je m'inscris ! (gratuit)
Voir le flux RSS

Le Blog d'un Ninja codeur

[Actualit�] Les bases de l'asynchrone en JavaScript

Note : 10 votes pour une moyenne de 3,40.
par , 01/08/2016 � 09h00 (8608 Affichages)
Nom : 1024.png
Affichages : 41489
Taille : 17,1 Ko

JavaScript bien qu'omnipr�sent de nos jours reste un langage tr�s d�cri� � cause notamment de nombreuses approximations dans les sp�cifications de sa syntaxe. Mais il serait simpliste et erron� de croire que le succ�s de ce langage n'est d� qu'� un ph�nom�ne de mode (cela fait une vingtaine d'ann�es que cela dure), ou que ses partisans sont de mauvais d�veloppeurs r�pandant de mauvaises pratiques de programmation.

Car au-del� des concepts phares comme l'h�ritage par prototype qui est � mon go�t survendu, la v�ritable force du langage ne r�side pas vraiment en lui, mais autour. Cette force, c'est son fonctionnement asynchrone dont les fondements ne sont pas toujours bien compris.


JavaScript : monothread et asynchrone

JavaScript est un langage qui a �t� pens� pour �voluer dans un environnement monothread et asynchrone.

Le terme thread pourrait �tre traduit en premi�re approximation par processus. Le fait que le moteur JavaScript (grosso modo l'interpr�teur JavaScript) soit monothread signifie que le moteur ne peut interpr�ter qu'une seule et unique instruction � la fois, via sa seule et unique pile d'ex�cution (Call Stack). Le principal avantage de ceci �tant la simplicit�.

Le terme asynchrone fait r�f�rence au comportement de certains traitements dans JavaScript qui peuvent �tre d�l�gu�s en dehors du moteur. Dans le cas d'une page Web, les traitements asynchrones seront d�l�gu�s au navigateur. � noter que bien que le moteur JavaScript soit monothread, l'h�te (eg. le navigateur ou NodeJS) peut lui �tre multithreads. Les threads pouvant �tre l'application JavaScript en cours, le rendu de l'interface utilisateur (UI), la gestion des entr�es/sorties (IO), etc.

Sans cette possibilit� de r�aliser des appels asynchrones, une application JavaScript serait condamn�e � bloquer le navigateur le temps de son ex�cution.

Nom : jsblocking.png
Affichages : 35651
Taille : 10,4 Ko
Notification de blocage de Firefox par un script


Circuit de l'asynchrone

L'asynchrone en JavaScript repose sur un circuit partant de la pile d'ex�cution, sortant du moteur JavaScript via les API du syst�me h�te (Host APIs) qui peut �tre le navigateur ou NodeJS, la file d'attente des callbacks (Callback Queue), la boucle des �v�nements (Event Loop), pour enfin revenir au moteur JavaScript sur la pile d'ex�cution.

Il est important de noter que le seul composant du moteur JavaScript directement impliqu� dans le circuit de l'asynchrone est la pile d'ex�cution. Les autres composants que sont les API du syst�me h�te, la file d'attente des callbacks et la boucle des �v�nements ne font pas � proprement parler partie de ce moteur JavaScript.

Il est ainsi possible de dire que JavaScript est un peu plus qu'un langage, c'est aussi une architecture.

Nom : circuitasynchrone_empty.png
Affichages : 36216
Taille : 24,2 Ko
Composants du circuit de l'asynchrone

Pile d'ex�cution

Un programme comporte g�n�ralement des fonctions appelant d'autres fonctions (ou s'appelant elles-m�mes). Le r�le de la pile d'ex�cution est d'assurer le suivi de la cha�ne d'appel en m�morisant la fonction et son contexte d'ex�cution (variables locales et param�tres d'appel). Un appel d'une fonction A() dans le contexte global empilera un premier niveau sur la pile d'ex�cution. Si cette fonction A() appelle en son sein une fonction B(), alors un second niveau sera empil� sur la pile. Et si cette fonction B() appelle une fonction C(), alors un troisi�me niveau sera empil� sur la pile. Un niveau de la pile n'est retir� que lorsque la fonction appel�e a termin� son ex�cution. C'est pourquoi lors d'appels r�cursifs mal impl�ment�s, il est possible de d�passer la capacit� de la pile et obtenir le fameux message d'erreur � stack overflow �.
Code javascript : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function A() {
    // Etat 1
    B();
    // Etat 5
}
 
function B() {
    // Etat 2
    C();
    // Etat 4
}
 
function C() {
    // Etat 3
}
 
// Etat 0
A();
// Etat 6
Appels imbriqu�s de fonctions

Nom : piledexecution.png
Affichages : 35820
Taille : 15,9 Ko

�tats successifs de la pile d'ex�cution lors d'appels imbriqu�s

APIs du syst�me h�te

Le syst�me h�te (eg. navigateur, NodeJS) fournit toute une panoplie de fonctions et d'objets (API) au moteur JavaScript pour interagir avec lui ou avec le syst�me d'exploitation. Certaines de ces fonctions sont asynchrones comme XMLHttpRequest.send(), FileReader.readFile() dans le domaine des acc�s aux ressources ou encore le listener du DOM pour ce qui est de la gestion des �v�nements, asynchrones par essence.

Le programme principal JavaScript doit avoir la possibilit� de savoir si un traitement asynchrone qu'il a appel� est termin� puis d'exploiter le r�sultat de ce traitement asynchrone en cons�quence. C'est l� qu'interviennent les fonctions callbacks. Il est courant en JavaScript que les callbacks soient des fonctions anonymes pass�es en param�tre et d�finies au moment m�me de l'appel de la fonction asynchrone.

Code javascript : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
var req = new XMLHttpRequest();
req.open('GET', 'http://www.mozilla.org/', true);
req.onreadystatechange = function callback(aEvt) { // fonction callback
  if (req.readyState == 4) {
     if(req.status == 200)
      dump(req.responseText);
     else
      dump("Erreur pendant le chargement de la page.\n");
  }
};
req.send(null); // traitement asynchrone
Requ�te HTTP asynchrone au format XML sous un navigateur

Code javascript : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
var fs = require('fs');
 
// traitement asynchrone
fs.readFile('DATA', 'utf8', function callback(err, contents) { // fonction callback
    console.log(contents);
});
Lecture asynchrone d'un fichier sous NodeJS

File d'attente des �v�nements

Une fois que le traitement asynchrone est termin� ou qu'un �v�nement particulier survient, la callback qui a �t� fournie en param�tre est ins�r�e dans la file d'attente des callbacks avant d'�tre prise en compte par la boucle des �v�nements.

Boucle des �v�nements

La boucle des �v�nements a pour but de surveiller l'�tat de la pile d'ex�cution. Si cette derni�re est vide d'instruction � ex�cuter, la boucle des �v�nements d�placera la callback en attente dans la file vers la pile d'ex�cution, permettant � cette callback d'�tre ainsi ex�cut�e.


D�roulement

Pour mieux illustrer l'implication des diff�rents composants dans un appel asynchrone, nous allons nous d�finir une fonction getData() qui appellera la fonction asynchrone standard setTimeout().

Code javascript : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var k = 0;
 
// Définition de la fonction getData()
 
function getData(callback) {
    console.log('getData()');
 
    setTimeout(function setTimeoutCB(counter) { // callback asynchrone
        console.log('setTimeoutCB()');
        callback(null, counter);
    }, 500, ++k);
}
 
// Appel de la fonction getData()
 
getData(function getDataCB(error, data) { // callback synchrone
    console.log('getDataCB()');
 
    console.log('data: ', data);
});

On peut constater dans le code ci-dessus, que la fonction setTimeout() appel�e � l'int�rieur de la fonction getData() appelle une fonction callback que nous avons nomm�e setTimeoutCB() pour la clart� du propos, mais qui aurait tr�s bien pu �tre anonyme.

Cette fonction setTimeoutCB() a ici pour t�che d'appeler la fonction callback() qui est un param�tre de la fonction getData(). C'est une des caract�ristiques des fonctions callbacks.

Lors de l'appel de la fonction getData(), une fonction callback getDataCB() lui est fournie en param�tre.

Regardons ce qu'il se passe lors de cet appel.

Nom : circuitasynchrone.png
Affichages : 36854
Taille : 35,5 Ko

(1) Apr�s que les fonctions getData() puis setTimeout() ont �t� empil�es sur la pile d'ex�cution, la fonction setTimeout() qui fait partie de l'API du navigateur, est appel�e et est prise en charge par celui-ci de fa�on asynchrone. � noter que cet appel � la fonction setTimeout() est la derni�re instruction directement ex�cut�e par le programme principal qui arrive ici � son terme. � ce moment, la pile d'ex�cution est vide.

(2) Le d�compte du d�lai s'effectue dans un thread � part, et lorsque le d�lai est �puis�, la fonction callback qui a �t� pass�e en param�tre de setTimeout(), setTimeoutCB(), est envoy�e vers la file d'attente. Notons que les param�tres de setTimeoutCB() sont fournis par setTimeout(). Ici, il s'agit juste d'un compteur num�rique valant 1, mais avec d'autres fonctions asynchrones, ce pourrait �tre un message d'erreur ou des donn�es binaires. L'important est d'avoir � l'esprit que les param�tres de la fonction callback sont fournis par la fonction asynchrone appelante.

(3) La boucle des �v�nements d�tecte la pr�sence d'une callback, setTimeoutCB(), dans la file d'attente, et s'assure que la pile d'ex�cution est bien vide. Si c'est le cas, la boucle des �v�nements envoie la callback sur la pile d'ex�cution o� elle est ex�cut�e.

Suite � cela, ce qui n'est pas sch�matis�, c'est l'empilement par dessus setTimeoutCB(), de la fonction callback() qui est le param�tre de getData() faisant r�f�rence � getDataCB(). Le fait que setTimeoutCB() ait toujours acc�s au param�tre callback vient de la propri�t� des fermetures en JavaScript (cf. article). La fonction setTimeoutCB() n'�tant pas elle une fonction asynchrone, contrairement � setTimeout(), il n'y a pas d'appel � l'API du navigateur, pas de passage par la file d'attente et pas d'intervention de la boucle des �v�nements pour ex�cuter la fonction. Il s'agit l� de traitements synchrones qui restent donc sous l'enti�re responsabilit� du moteur JavaScript.

Remarque : N'h�sitez pas � relire plusieurs fois le code, le sch�ma et les explications pour bien visualiser le d�roulement.


Conclusion

Les m�canismes de l'asynchrone en JavaScript ne sont pas tr�s compliqu�s � comprendre, mais non triviaux � expliquer comme on vient de le voir. Il n'existe finalement pas �norm�ment de ressources � ce sujet sur le Web. J'esp�re tout de m�me que ce bref expos� vous aura aid� � mieux comprendre ce qui se d�roule � sous le capot � lorsque vous utiliserez des fonctions asynchrones et des callbacks.

Il existe un outil en ligne sur le Web qui permet de visualiser dynamiquement le d�roulement d'un code asynchrone. Son auteur, Philip Roberts, explique en anglais plus en d�tail le fonctionnement de l'asynchrone dans cette vid�o ci-dessous et dont cet article s'est largement inspir�.


N'h�sitez pas � partager ce billet si vous l'avez trouv� utile.

Bon d�veloppement !

Envoyer le billet � Les bases de l'asynchrone en JavaScript � dans le blog Viadeo Envoyer le billet � Les bases de l'asynchrone en JavaScript � dans le blog Twitter Envoyer le billet � Les bases de l'asynchrone en JavaScript � dans le blog Google Envoyer le billet � Les bases de l'asynchrone en JavaScript � dans le blog Facebook Envoyer le billet � Les bases de l'asynchrone en JavaScript � dans le blog Digg Envoyer le billet � Les bases de l'asynchrone en JavaScript � dans le blog Delicious Envoyer le billet � Les bases de l'asynchrone en JavaScript � dans le blog MySpace Envoyer le billet � Les bases de l'asynchrone en JavaScript � dans le blog Yahoo

Mis � jour 03/08/2016 � 17h02 par ClaudeLELOUP

Cat�gories
D�veloppement , Javascript , D�veloppement Web , DotNET , C#

Commentaires

  1. Avatar de MrJoy
    • |
    • permalink
    Un tout tout grand merci pour cet article et le partage de la vid�o! Cela m'aura permis de mieux comprendre tout le fonctionnement intrins�que de Javascript et de la participation du navigateur � la f�te