Node.js fournit une librairie pour gérer les évènements : require ('event'). Les évènements sont le véritable centre nerveux d'une application asynchrone dans Node.js. Ils émettrent des signaux qui associés à des callback, orientent et cadencent le déroulement du programme.
Exemple:
Les opérations pour interroger une page WEB les suivantes:
1) Se connecter au serveur
2) Lancer la requête
3) Traiter les entêtes
4) Traiter le corps de la page
4) Se déconnecter
Pour ne pas bloquer le système entre chaque étape notamment celle qui attend la réponse du serveur, il est judicieux de programmer l'émission de signaux à des moments clés du cycle. Exemple 'j'ai reçu les entetes' , 'j'ai reçu les données de la page' et 'le serveur m'indique que c'est terminé'. pour chacun de ces signaux, il sera nécessaire de les 'ecouter' et de réagir en lançant les actions associées (callback) .
Ce système est composé de deux parties: l'emetteur de signaux (evenement) et le recepteur (listener) qui attend les évenements et lance les actions (callback ) prévues.
Les API de base de node.js sont livrées avec une gestion d’évènement, en charge pour le developpeur de réaliser la partie qui va traiter ces évènements.
(Exemple API HTTP: documentation ici )
Avec ici un exemple de récepteur sur l’évènement 'data':
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
Comment mettre en place son propre système d’évènement.La partie réception et traitement est la plus facile en voici un exemple:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var signal=require('./signal.js'); | |
var sonde = new signal(); | |
// mise en place des listener et des fonctions de retour | |
sonde.on('ici',function(msg){ | |
console.log(msg)} ); | |
sonde.on('lemoment',function(msg){ | |
console.log(msg)} ); | |
// lancement des opérations | |
sonde.temporisateur(); | |
sonde.maint(); |
Deux récepteurs sont mis à l'écoute.
La partie émission des signaux.
Node.js fournit la libraire 'event' et voici un exemple en coffeescript qui fonctionne avec le programme précédent:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{EventEmitter} = require('events') | |
class Signal extends EventEmitter | |
maint: -> | |
@emit 'ici','maintenant' | |
temporisateur: -> | |
setTimeout ( => @emit 'lemoment',"le message est arrive") , 5000 | |
module.exports = Signal |
Il ne faut pas grand chose ! C'est la magie de coffeescript et la puissance de node.js.
Pourquoi la magie de coffesscript ?
Parce en javascript écrit à la main, dans les règles de l'art, cela donne:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var events = require('events'); | |
/* | |
* Define a non-enumerable function to allow ease of extending objects. | |
*/ | |
Object.defineProperty(Object.prototype, "extend", { | |
enumerable: false, | |
value: function (from) { | |
var props = Object.getOwnPropertyNames(from); | |
var dest = this; | |
props.forEach(function(name) { | |
var descriptor = Object.getOwnPropertyDescriptor(from, name); | |
Object.defineProperty(dest, name, descriptor); | |
}); | |
return this; | |
} | |
}); | |
/* | |
* Define the main api_request contsructor, also inheirit from EventEmmitter | |
*/ | |
function signal (data) { | |
// Call EventEmitter constructor on this context | |
events.EventEmitter.call(this); | |
} | |
signal.super_ = events.EventEmmitter; | |
signal.prototype = Object.create( | |
events.EventEmitter.prototype, | |
{ | |
constructor: { | |
value: signal, | |
enumerable: false | |
} | |
} | |
); | |
signal.prototype.temporisateur = function() { | |
var self = this; | |
setTimeout(function(){self.emit('lemoment',"mon message");},5000); | |
}; | |
signal.prototype.maint = function() { | |
this.emit('ici',"maintenant"); | |
}; | |
module.exports = signal; |
La premiere fonction sert à construire proprement des objets, sans effet de bord sur d'autres modules.
(copiée sur api_request )
Il est intéressant de voir que tous ces problèmes de constructeur sont pris en charge par coffescript comme le montre le javascript issu du programme coffee.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
var EventEmitter, Signal, querystring; | |
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { | |
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } | |
function ctor() { this.constructor = child; } | |
ctor.prototype = parent.prototype; | |
child.prototype = new ctor; | |
child.__super__ = parent.prototype; | |
return child; | |
}, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; | |
EventEmitter = require('events').EventEmitter; | |
querystring = require('querystring'); | |
Signal = (function() { | |
__extends(Signal, EventEmitter); | |
function Signal() { | |
Signal.__super__.constructor.apply(this, arguments); | |
} | |
Signal.prototype.maint = function() { | |
return this.emit('ici', 'maintenant'); | |
}; | |
Signal.prototype.temporisateur = function() { | |
return setTimeout((__bind(function() { | |
return this.emit('lemoment', "le message est arrive"); | |
}, this)), 5000); | |
}; | |
return Signal; | |
})(); | |
module.exports = Signal; | |
}).call(this); |
Aussi, coffescript n'est pas un simple générateur de code. Il met en place les bonnes pratiques et vous économise des lignes de code.