La promesse des promises en JavaScript

L'implémentation de la spécification ECMAScript 2015 sur laquelle JavaScript est fondé a conduit à introduire un nouvel objet standard en JavaScript : Promise. Il s'agit bien d'un objet standard, c'est-à-dire propre au langage comme String et non au navigateur, comme XMLHttpRequest.
Cet objet permet de faciliter et de sécuriser l'écriture d'un appel à une fonction asynchrone, c'est-à-dire à une fonction qui rend la main sans avoir encore retourné son résultat, s'engageant à signaler au programme qui l'a appelée quand ce résultat sera disponible, par exemple en appelant une fonction que le programme lui a fournie - une callback.
Le Serment des Horaces par David
Tout développeur JavaScript a très probablement déjà utilisé ce type de fonction, notamment pour charger des fichiers via l'objet XMLHttpRequest, ou pour déclencher une action après expiration d'un timer programmé via window.setTimeout ().
Avec l'objet Promise, l'asynchronisme a en quelque sorte été dégagé des objets qui viennent d'être cités pour accéder au rang d'aspect fonctionnel fondamental de JavaScript, au même titre que l'héritage basé sur les prototypes ou les closures. Partant tout développeur JavaScript doit maîtriser l'asynchronisme.
Pour autant, qui met le nez dans la spécification ne peut être que rapidement rebuté par l'opacité de cette dernière. Fort heureusement, il existe de nombreuses autres sources auxquelles se référer. Apportons ici une modeste contribution avec une présentation détaillée du système des promises destinée à qui découvre le sujet.
Mise à jour du 06/10/2021 : Correction d'une erreur mineure à la fin du propos sur le chaînage.
Continuer la lecture de "La promesse des promises en JavaScript"
La promesse des promises en JavaScript

Closures pour gérer les événements en JavaScript

La fonction addEventListener () permet d'associer une fonction (le gestionnaire d'événement) à un événement. Lorsque l'événement survient, le navigateur appelle le gestionnaire d'événement en lui transmettant un unique argument sous la forme d'un objet décrivant l'événement.
Comment transmettre autre chose à ce gestionnaire, comme par exemple une référence sur un objet spécifique ?

Continuer la lecture de "Closures pour gérer les événements en JavaScript"

Closures pour gérer les événements en JavaScript

Inversion de contrôle pour gérer les événements

Le développement d'une IHM (interface homme-machine) conduit très rapidement à associer un traitement à une séquence d'actions. Par exemple, attendre que l'utilisateur presse la touche "Suppr" pour initier la suppression d'un élément graphique, puis qu'il clique sur un élément graphique pour supprimer ce dernier. On parle ici d'un automate qui est dans un état d'attente de la pression de la touche "Suppr", puis dans un état d'attente d'un clique sur un élément avant de revenir à son état initial.
La solution qui vient à l'esprit est de s'appuyer sur la gestion des événements du système. Il s'agit d'associer un gestionnaire d'événement à chacun des événements qui entraîne un possible changement d'état de l'automate, et de gérer dans ce gestionnaire le changement d'état. Pour reprendre l'exemple, supposons qu'il s'agisse de permettre de supprimer un élément HTML d'identifiant "tagElement" en pressant la touche Suppr, puis en cliquant sur l'élément. Le code JavaScript est alors le suivant :
var STATE_IDLE = 0;
var STATE_KEYPRESSED = 1;
var state;

function run () {
	document.body.addEventListener ("keypress", handlerKeyPress, false);
	document.getElementById ("tagElement").addEventListener ("click", handlerMouseClick, false);
	state = STATE_IDLE;
}

function handlerKeyPress (e) {
	switch (state) {
		case STATE_IDLE :
			if (e.key != "Delete")
				break;
			state = STATE_KEYPRESSED;
			document.getElementById ("tagElement").innerHTML = "Cliquez-moi maintenant";
			break;
	}
}

function handlerMouseClick (e) {
	switch (state) {
		case STATE_KEYPRESSED :
			document.getElementById ("tagElement").innerHTML = "Vous m'avez supprimé ! (pressez Suppr pour recommencer)";
			state = STATE_IDLE;
			break;
	}
}
Cliquez ici pour accéder à une page de test minimaliste. Vous pourrez visualiser le code et le récupérer pour travailler avec.
Le problème est que le code de l'automate est réparti dans les deux gestionnaires d'événement impliqués. En soi, c'est déjà compliqué. Ça le devient encore plus tandis que l'IHM s'enrichit et que les automates de ce type se multiplient et se complexifient. N'est-il pas possible de regrouper le code d'un automate dans une seule fonction spécifique ?

Continuer la lecture de "Inversion de contrôle pour gérer les événements"

Inversion de contrôle pour gérer les événements