Découvrez le développement JavaScript asynchrone linéaire, avec yld
Si vous avez déjà fait du JavaScript asynchrone, vous avez certainement connaissance de techniques de traitement de la réponse.
Les callbacks
Ils vous permettent de traiter une réponse après l'exécution d'une fonction asynchrone, en cas d'erreur ou non.
Ils ont pour défauts de devoir avoir des fonctions gérant l'échec ou la réussite et de pousser vers un développement plein de fonctions imbriquées, nuisant à sa lisibilité et l'espace des arguments de votre fonction est pollué par les callbacks.
Pour palier cela, une autre méthode est apparue, les promesses (promises, en anglais).
Les promises
Les promesses ont une structure permettant aussi de gérer l'échec ou la réussite de l'exécution d'une fonction, d'exécuter des fonctions pendant la progression de l'exécution, etc.
Elles se différencient par le fait qu'une promesse est un objet auquel on passe tout un tas de fonctions, via ses méthodes, afin de gérer les différents états de l'exécution.
On se retrouve donc avec énormément de fonctions dans son code avec, parfois, des références internes.
Cela a tendance à déstructurer votre code de telle sorte que sa relecture peut devenir une vraie gymnastique cérébrale.
Le mot-clé yield
Me tenant à jour concernant les avancées du JavaScript, j'ai découvert, parmi les propositions de la future norme ECMAScript 6, le mot-clé yield.
Ce mot-clé, une sorte de return particulier, permet de créer des fonctions retournant un générateur, comprenez par là que la liste d'instructions que contient votre fonction fera un arrêt à chaque yield qu'elle contient, jusqu'à ce que vous appeliez le yield suivant, via la méthode next().
Exemple :
1 2 3 4 5 6 7 8 9 10 11 12 13
| var generate, generator;
generate = function generate(value) {
yield 'Hello ' + value;
};
generator = generate('World');
// on appelle le yield suivant du générateur, après 2 secondes
setTimeout(function () {
// renverra "Hello World" dans votre console, après les 2 secondes
console.log(generator.next());
}, 2000); |
Ces générateurs ont aussi une une méthode send().
Celle-ci permet d'envoyer une liste de valeurs au générateur, à un moment donné pendant le parcours des yield qu'il contient.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| var generate, generator;
generate = function generate() {
var message, response;
message = 'Hello ';
response = yield message;
yield message + response;
};
generator = generate();
// on démarre le générateur, affichera "Hello "
console.log(generator.next());
// on appelle le yield suivant du générateur, après 2 secondes
setTimeout(function () {
// renverra "Hello World" dans votre console, après les 2 secondes
console.log(generator.send('World'));
}, 2000); |
Enfin, sachez que les générateurs ont aussi une méthode close(), afin de libérer la mémoire.
Le yielded style programming
Partant de cette découverte, je me suis dit qu'il devrait être possible d'affecter à une variable du contexte (scope) courant, le résultat d'une fonction asynchrone et d'ensuite poursuivre le processus.
C'est ainsi qu'est né yld (prononcez yielded).
Il s'agit d'un outil vous permettant de transformer un générateur en une liste d'instructions s'exécutant l'une après l'autre, comme s'il s'agissait d'une simple fonction mais attendant la réponse de fonctions asynchrones, quand c'est nécessaire.
De plus, il ajoute une notion de relation entre les différents scopes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| var asyncFn1, asyncFn2;
asyncFn1 = yld(function (a, b) {
var child, response;
if (isNaN(a) || isNaN(b)) {
// stoppe le processus immédiatement et renvoie une erreur avec le message spécifié
this.error = 'Invalid values';
}
// this.yld est utilisable comme yld
child = yield this.yld(asyncFn2)(a);
response = yield child.send(b);
console.log(response); // 3
});
asyncFn2 = function (a) {
var b, parent;
parent = this.parent;
// retourne le scope courant au scope parent
b = yield parent.send(this);
// retourne la réponse au scope parent
yield setTimeout(function () {
parent.send(a + b);
}, 3000);
};
asyncFn1(1, 2); |
Comme vous pouvez le constater, il n'y a que très peu de fonctions, vous passez uniquement les arguments dont vos fonctions ont besoin et, surtout, le processus s'interrompt à chaque yield, vous permettant de récupérer une valeur sur la même ligne que l'appel à une fonction asynchrone, comme si elle ne l'était pas.
N.B. : Le mot-clé yield étant une possibilité d'amélioration future du JavaScript, il est possible que yld ne s'exécute pas encore partout, néanmoins, yld est déjà conçu pour pouvoir s'exécuter en navigateur et sous Node.js.
Pour tester les différents exemples, je vous recommande l'utilisation d'un Firefox à jour.
EDIT : Le plus facile, pour vos tests, c'est via la console de Firebug.
Sinon, vous pouvez l'embarquer, dans votre HTML via
<script type="application/javascript;version=1.7"></script>
Où le 1.7 est, évidemment, la version minimale.
Source : https://github.com/Lcfvs/yld
Malgré l'habitude évidente qu'il vous faudra pour complètement en tirer avantage, trouvez-vous que cela peut réellement améliorer la lisibilité de votre code?
Sinon, qu'y reprochez-vous?
Partager