J'écris une application Node.js en utilisant un émetteur d'événement global. En d'autres termes, mon application est entièrement construite autour des événements. Je trouve que ce type d'architecture fonctionne très bien pour moi, à l'exception d'un cas latéral que je décrirai ici.Comment éviter le besoin de retarder l'émission de l'événement au prochain tick de la boucle d'événement?
Notez que je ne pense pas que la connaissance de Node.js est nécessaire pour répondre à cette question. Par conséquent, je vais essayer de le garder abstrait.
Imaginez la situation suivante:
- Un émetteur d'événement mondial (appelé
mediator
) permet aux modules individuels pour écouter les événements à l'échelle application. - Un serveur HTTP est créé, acceptant les demandes entrantes.
- Pour chaque requête entrante, un émetteur d'événement est créé pour faire face à des événements spécifiques à cette demande
Un exemple (uniquement pour illustrer cette question) d'une requête entrante:
mediator.on('http.request', request, response, emitter) {
//deal with the new request here, e.g.:
response.send("Hello World.");
});
Jusqu'à présent , tellement bon. On peut désormais étendre cette application en identifiant l'URL demandée et d'émettre des événements appropriés:
mediator.on('http.request', request, response, emitter) {
//identify the requested URL
if (request.url === '/') {
emitter.emit('root');
}
else {
emitter.emit('404');
}
});
Après cela on peut écrire un module qui traitera une demande de racine.
mediator.on('http.request', function(request, response, emitter) {
//when root is requested
emitter.once('root', function() {
response.send('Welcome to the frontpage.');
});
});
Cela semble bien, non? En fait, c'est code potentiellement cassé. La raison en est que la ligne emitter.emit('root')
peut être exécutée avant la ligne emitter.once('root', ...)
. Le résultat est que l'auditeur n'est jamais exécuté.
On pourrait faire face à cette situation particulière en retardant l'émission de l'événement root
à la fin de la boucle d'événement:
mediator.on('http.request', request, response, emitter) {
//identify the requested URL
if (request.url === '/') {
process.nextTick(function() {
emitter.emit('root');
});
}
else {
process.nextTick(function() {
emitter.emit('404');
});
}
});
La raison pour laquelle cela fonctionne est parce que l'émission est maintenant retardée jusqu'à ce que la boucle d'événements en cours a terminé, et donc tous les auditeurs ont été enregistrés.
Cependant, il y a beaucoup de problèmes avec cette approche: architecture basée
- l'un des avantages d'un tel événement est que des modules d'émission ne ont pas besoin de savoir qui est à l'écoute de leurs événements. Par conséquent, il ne devrait pas être nécessaire de décider si l'émission de l'événement doit être retardée, car on ne peut pas savoir ce qui va écouter l'événement et s'il a besoin d'être retardé ou non.
- ce code de manière significative les encombre et complexifie (comparer les deux exemples)
- il aggrave probablement la performance
En conséquence, ma question est: comment peut-on éviter la nécessité de retarder l'émission d'événements à la prochaine tique de la boucle d'événement, comme dans la situation décrite?
Mise à jour 19-01-2013
Un exemple illustrant pourquoi ce comportement est utile: pour permettre à une requête HTTP à traiter en parallèle.
mediator.on('http.request', function(req, res) {
req.onceall('json.parsed', 'validated', 'methodoverridden', 'authenticated', function() {
//the request has now been validated, parsed as JSON, the kind of HTTP method has been overridden when requested to and it has been authenticated
});
});
Si chaque événement comme json.parsed
émettrait la demande initiale, alors ce qui précède n'est pas possible, car chaque événement est lié à une autre demande et vous ne pouvez pas écouter une combinaison d'actions exécutées en parallèle pour une demande spécifique.
Veuillez indiquer si quelque chose doit être développé plus avant. – Tom
Configurez tous les événements au démarrage. N'attachez pas d'événements (ceux du contrôle de flux) après le démarrage de l'application. Ne joignez pas d'événements lors de l'exécution pour chaque requête. – Raynos