Dans Node, de nombreux objets émettent des événements. Par exemple, un serveur TCP transmettra un événement "Connexion" chaque fois qu'un client demande une connexion, et par exemple, chaque fois qu'un élément de données est lu, le système de fichiers transmettra un événement "Data". Ces objets sont appelés émetteurs d'événements dans le nœud. L'émetteur d'événements permet aux programmeurs de s'abonner à des événements d'intérêt et de lier la fonction de rappel aux événements associés, de sorte que la fonction de rappel est appelée chaque fois que l'émetteur d'événements émet un événement. Le mode Publish / Sbonned est très similaire au mode GUI traditionnel, comme le programme recevra des notifications correspondantes lorsque le bouton est cliqué. En utilisant ce modèle, les programmes de serveur peuvent réagir lorsque certains événements se produisent, tels que la connexion client, les données disponibles sur la prise ou le fichier fermé.
Vous pouvez également créer votre propre émetteur d'événements. En fait, Node fournit une pseudo-classe EventEmitter spéciale qui peut être utilisée comme classe de base pour créer votre propre émetteur d'événements.
Comprendre le mode de rappel
La programmation asynchrone n'utilise pas de valeurs de retour de fonction pour indiquer la fin d'un appel de fonction, mais adopte un style de passe ultérieur.
"Style de passage à la continuation" (CPS: style de passage à continuation) est un style de programmation et le contrôle des processus est explicitement transmis à l'opération suivante ...
Les fonctions de style CPS accepteront une fonction comme un paramètre supplémentaire. Cette fonction est utilisée pour signaler explicitement le prochain processus de contrôle du programme. Lorsque la fonction CPS calcule sa "valeur de retour", il appellera la fonction qui représente le prochain processus du programme et prendra la "valeur de retour" de la fonction CPS comme paramètre.
De Wikipedia - http://en.wikipedia.org/wiki/contination-passing_style
Dans ce style de programmation, chaque fonction appellera une fonction de rappel après l'exécution, afin que le programme puisse continuer à s'exécuter. Vous comprendrez plus tard que JavaScript est très adapté à ce style de programmation. Voici un exemple de chargement de fichiers en mémoire sous Node:
La copie de code est la suivante:
var fs = require ('fs');
fs.readfile ('/ etc / passwd', fonction (err, fileContent) {
if (err) {
lancer err;
}
console.log («contenu de fichier», fileContent.toString ());
});
Dans cet exemple, vous passez une fonction anonyme en ligne comme le deuxième paramètre de Fs.Readfile. En fait, cela utilise la programmation CPS car vous remettez le processus ultérieur de l'exécution du programme à la fonction de rappel.
Comme vous pouvez le voir, le premier paramètre de la fonction de rappel est un objet d'erreur. Si une erreur se produit dans le programme, ce paramètre sera une instance de la classe d'erreur. Il s'agit d'un modèle commun pour la programmation CPS dans le nœud.
Comprendre le mode émetteur d'événements
Dans le mode de rappel standard, une fonction est transmise comme paramètre à la fonction à exécuter. Ce mode fonctionne très bien dans les scénarios où le client doit être informé une fois la fonction terminée. Cependant, si plusieurs événements se produisent lors de l'exécution d'une fonction ou des événements se produisent plusieurs fois, ce modèle ne convient pas. Par exemple, si vous souhaitez être informé chaque fois que le socket reçoit des données disponibles, vous constaterez que le mode de rappel standard n'est pas très utile dans ce scénario. À l'heure actuelle, le mode émetteur d'événements est utile. Vous pouvez utiliser un ensemble d'interfaces standard pour séparer clairement le générateur d'événements et l'écouteur d'événements.
Lorsque vous utilisez le mode générateur d'événements, deux objets ou plus sont impliqués: les émetteurs d'événements et un ou plusieurs écouteurs d'événements.
Un émetteur d'événements, comme son nom l'indique, est un objet qui peut générer des événements. L'auditeur d'événements est lié à l'émetteur d'événements pour écouter des types d'événements spécifiques, comme l'exemple suivant:
La copie de code est la suivante:
var req = http.request (options, fonction (réponse) {
réponse.on ("data", fonction (data) {
console.log ("certaines données de la réponse", données);
});
réponse.on ("end", function () {
console.log ("réponse terminée");
});
});
req.end ();
Ce code démontre deux étapes nécessaires lors de la création d'une demande HTTP pour accéder à un serveur HTTP distant à l'aide de l'API HTTP.Request de Node (voir le chapitre ultérieur). La première ligne adopte le "style de passage à continuation" (CPS: style de passage à la continuation), passant une fonction en ligne qui sera appelée lorsque HTTP répond. L'API de demande HTTP utilise CPS ici car le programme doit continuer à effectuer des opérations ultérieures après l'exécution de la fonction HTTP.Request.
Lorsque Http.Request est exécuté, la fonction de rappel anonyme sera appelée et l'objet de réponse HTTP lui est transmis en tant que paramètre. Cet objet de réponse HTTP est un émetteur d'événements. Selon le document du nœud, il peut émettre de nombreux événements, y compris les données et la fin. Les fonctions de rappel que vous vous inscrivez seront appelées chaque fois que l'événement se produit.
En leçon, utilisez le mode CPS lorsque vous devez retrouver les droits d'exécution une fois l'opération demandée terminée et utiliser le mode d'émetteur d'événements lorsque les événements peuvent se produire plusieurs fois.
Comprendre les types d'événements
Les événements transmis ont un type représenté par une chaîne. L'exemple précédent contient deux types d'événements: "données" et "end", qui sont toutes les chaînes définies par l'émetteur d'événements. Cependant, il est conventionnellement constitutif que les types d'événements sont généralement composés de mots minuscules qui ne contiennent pas de caractères vides.
Vous ne pouvez pas utiliser de code pour déduire quels types d'événements que l'émetteur d'événements peut générer, car l'API de l'émetteur d'événements n'a pas de mécanisme d'introspection, de sorte que l'API que vous utilisez doit avoir une documentation pour indiquer qu'elle peut émettre ces types d'événements.
Une fois qu'un événement a eu lieu, l'émetteur d'événements appellera l'auditeur lié à l'événement et transmettra les données pertinentes à l'auditeur en tant que paramètre. Dans l'exemple précédent Http.Request, la fonction de rappel d'événements "Data" accepte un objet de données comme premier et seul paramètre, tandis que "fin" n'accepte aucune donnée. Ces paramètres dans le cadre du contrat de l'API sont également définis subjectivement par l'auteur de l'API. Les signatures de paramètres de ces fonctions de rappel seront également expliquées dans la documentation de l'API de chaque émetteur d'événements.
Bien que l'émetteur d'événements soit une interface servant tous les types d'événements, l'événement "Erreur" est une implémentation spéciale dans le nœud. La plupart des émetteurs d'événements dans Node généreront un événement "Erreur" lorsqu'une erreur se produit dans le programme. Si le programme n'écoute pas l'événement "Erreur" d'un émetteur d'événements, l'émetteur d'événements remarquera et lancera une exception non apprise à la hausse lorsque l'erreur se produit.
Vous pouvez exécuter le code suivant dans Node Perl pour tester l'effet, qui simule un émetteur d'événements qui peut générer deux événements:
La copie de code est la suivante:
var em = new (require ('events'). EventEMmitter) ();
em.emit ('event1');
em.emit ('error', nouvelle erreur ('mon erreur'));
Vous verrez la sortie suivante:
La copie de code est la suivante:
var em = new (require ('events'). EventEMmitter) ();
indéfini
> em.emit ('event1');
FAUX
> em.emit ('error', nouvelle erreur («mon erreur»));
Erreur: mon erreur
à Rep: 1: 18
sur replServer.eval (repl.js: 80: 21)
à Rep.js: 190: 20
sur replServer.eval (rep.js: 87: 5)
à l'interface. <Anonymous> (rep.js: 182: 12)
sur interface.emit (events.js: 67: 17)
sur interface._online (readline.js: 162: 10)
sur interface._line (readline.js: 426: 8)
sur interface._ttywrite (readline.js: 603: 14)
à ReadStream. <Nomymous> (readline.js: 82: 12)
>
Dans la ligne 2 du code, un événement appelé "Event1" est émis, sans aucun effet, mais lorsque l'événement "Erreur" est émis, l'erreur est jetée à la pile. Si le programme n'est pas en cours d'exécution dans l'environnement de la ligne de commande Perl, le programme se bloquera en raison d'une exception non revêtue.
Utilisation de l'API de l'émetteur d'événements
Tout objet qui implémente le mode d'émetteur d'événements (tel que la prise TCP, la demande HTTP, etc.) implémente l'ensemble de méthodes suivant:
La copie de code est la suivante:
.AddListener et .on - Ajouter un écouteur d'événements pour les événements du type spécifié
.once - lier un écouteur d'événements qui exécute une seule fois pour l'événement du type spécifié
.RemoveEventListener - Supprimer un auditeur lié à l'événement spécifié
.removealleventListener - Supprimer tous les auditeurs liés à l'événement spécifié
Présenons-les en détail ci-dessous.
Fonctions de rappel de liaison à l'aide de .AddListener () ou .on ()
En spécifiant le type d'événement et la fonction de rappel, vous pouvez enregistrer les actions effectuées lorsque l'événement se produit. Par exemple, s'il existe des blocs de données disponibles lorsqu'un fichier lit un flux de données, il émettra un événement "Data". Le code suivant montre comment passer une fonction de rappel pour permettre au programme de vous dire que l'événement de données s'est produit.
La copie de code est la suivante:
fonction reçueaTa (data) {
Console.log ("Got Data à partir du flux de fichiers:% j", données);
}
readStream.AddListener ("data", reçusaTa);
Vous pouvez également utiliser .on, qui n'est que l'abréviation de .AddListener. Le code suivant est le même que ce qui précède:
La copie de code est la suivante:
fonction reçueaTa (data) {
Console.log ("Got Data à partir du flux de fichiers:% j", données);
}
readStream.on ("data", reçoitaa);
Dans le code précédent, vous pouvez utiliser une fonction nommée définie à l'avance comme la fonction de rappel, et vous pouvez également utiliser une fonction anonyme en ligne pour simplifier le code:
La copie de code est la suivante:
readStream.on ("data", fonction (data) {
Console.log ("Got Data à partir du flux de fichiers:% j", données);
});
Comme mentionné précédemment, le nombre de paramètres et de signatures transmis à la fonction de rappel dépend de l'objet d'émetteur d'événements spécifique et du type d'événement. Ils ne sont pas standardisés. L'événement "Data" peut passer un objet de tampon de données, l'événement "Erreur" passe un objet d'erreur et l'événement "End" du flux de données ne transmet aucune donnée à l'écouteur d'événements.
Lier plusieurs auditeurs d'événements
Le mode d'émetteur d'émetteur permet à plusieurs écouteurs d'événements d'écouter le même type d'événement du même émetteur d'événements, tels que:
La copie de code est la suivante:
J'ai des données ici.
J'ai aussi des données ici.
L'émetteur d'événements est chargé d'invoquer tous les auditeurs liés au type d'événement spécifié dans l'ordre dans lequel l'auditeur est enregistré, c'est-à-dire:
1. Lorsqu'un événement se produit, l'auditeur de l'événement peut ne pas être appelé immédiatement, et il peut y avoir d'autres auditeurs d'événements appelés avant lui.
2. Il est anormal d'être jeté à la pile, ce qui peut être dû à un bogue dans le code. Lorsqu'un événement est transmis, si un écouteur d'événement lance une exception lorsqu'il est appelé, certains auditeurs d'événements peuvent ne jamais être appelés. Dans ce cas, l'émetteur d'événements capte l'exception et peut également le gérer.
Voir l'exemple suivant:
La copie de code est la suivante:
readStream.on ("data", fonction (data) {
lancer une nouvelle erreur ("quelque chose de mal s'est produit");
});
readStream.on ("data", fonction (data) {
console.log («J'ai aussi des données ici.»);
});
Parce que le premier écouteur lance une exception, le deuxième auditeur ne sera pas appelé.
Utilisez .reMoveListERner () pour supprimer un écouteur d'événements de l'émetteur d'événements
Si vous ne vous souciez plus d'un événement sur un objet, vous pouvez annuler l'écouteur d'événements enregistré en spécifiant le type d'événement et la fonction de rappel, comme ceci:
La copie de code est la suivante:
fonction reçueaTa (data) {
Console.log ("Got Data à partir du flux de fichiers:% j", données);
}
readStream.on ("data", reçoitaa);
// ...
readStream.RemoveListener ("data", reçu);
Dans cet exemple, la dernière ligne supprime un écouteur d'événements qui peut être appelé à tout moment dans le futur de l'objet d'émetteur d'événements.
Afin de supprimer l'auditeur, vous devez nommer la fonction de rappel, car le nom de la fonction de rappel est requis lors de l'ajout et de la suppression.
Utilisez .once () pour permettre l'exécution de la fonction de rappel au maximum une fois
Si vous souhaitez écouter un événement qui s'exécute au plus une fois, ou si vous êtes uniquement intéressé par la première fois qu'un événement se produit, vous pouvez utiliser la fonction .once ():
La copie de code est la suivante:
fonction reçueaTa (data) {
Console.log ("Got Data à partir du flux de fichiers:% j", données);
}
readStream.once ("data", reçusaTa);
Dans le code ci-dessus, la fonction reçus ne sera appelée qu'une seule fois. Si l'objet ReadStream émet un événement de données, la fonction de rappel ReçueaTA ne sera déclenchée qu'une seule fois.
C'est en fait juste une méthode pratique, car elle peut être implémentée très simplement, comme ceci:
La copie de code est la suivante:
var eventEMmitter = require ("Events"). EventEMmitter;
EventEmitter.prototype.once = fonction (type, rappel) {
var that = this;
this.on (Type, Function écouteur () {
That.reMoveListener (type, auditeur);
callback.Apply (que, arguments);
});
};
Dans le code ci-dessus, vous redéfinissez la fonction EventEmitter.prototype.on, et redéfinissez également la fonction une fois de chaque objet hérité de EventEmitter. Le code utilise simplement la méthode .on (). Une fois un événement reçu, utilisez .reMoveEventListener () pour annuler l'enregistrement de la fonction de rappel et appeler la fonction de rappel d'origine.
Remarque: le code précédent utilise la méthode function.apply (), qui accepte un objet et le prend comme contenu cette variable et un tableau de paramètres. Dans l'exemple précédent, le tableau de paramètres non modifié est transmis de manière transparente à la fonction de rappel via l'émetteur d'événements.
Supprimer tous les auditeurs d'événements de l'émetteur d'événements avec .reMovealLlistenners ()
Vous pouvez supprimer tous les écouteurs enregistrés sur le type d'événement spécifié de l'émetteur d'événements comme suit:
La copie de code est la suivante:
emiter.removealLlistenners (type);
Par exemple, vous pouvez annuler l'auditeur de tous les signaux d'interruption de processus comme ceci:
La copie de code est la suivante:
process.removealLlistenners ("Sigterm");
Remarque: En leçon, il est recommandé d'utiliser cette fonction uniquement que lorsque vous savez exactement ce qui est supprimé. Sinon, vous devez laisser d'autres parties de l'application supprimer la collection d'écoute d'événements, ou vous pouvez également laisser ces parties du programme prendre en charge de la suppression de l'auditeur eux-mêmes. Mais quoi qu'il arrive, cette fonction est toujours utile dans certains scénarios rares, comme lorsque vous vous préparez à fermer un émetteur d'événements ou à arrêter l'ensemble du processus de manière ordonnée.
Créer un émetteur d'événements
Les émetteurs d'événements rendent les interfaces de programmation plus générales d'une manière plus générale. Dans un mode de programmation commun et facile à comprendre, le client appelle directement diverses fonctions, tandis qu'en mode émetteur d'événements, le client est lié à divers événements, ce qui rendra votre programme plus flexible. (Note du traducteur: cette phrase n'est pas très confiante, publier le texte d'origine: l'émetteur d'événements offre un excellent moyen de rendre une interface de programmation plus générique. Lorsque vous utilisez un modèle de compréhension commun, les clients se lient aux événements au lieu d'invoquer des fonctions, ce qui rend votre programme plus flexible.)
De plus, en utilisant des émetteurs d'événements, vous pouvez également obtenir de nombreuses fonctionnalités, telles que la liaison de plusieurs auditeurs non apparentés sur le même événement.
Hérité de l'émetteur d'événements de nœud
Si vous êtes intéressé par le mode d'émetteur d'événements de Node et que vous avez l'intention de l'utiliser dans votre propre application, vous pouvez créer une pseudo-classe en héritant EventEmitter:
La copie de code est la suivante:
util = require ('util');
var eventEMmitter = require ('Events'). EventEMmitter;
// c'est le constructeur de MyClass:
var myClass = function () {
}
util.inherits (myclass, eventEmitter);
Remarque: util.inherits crée la chaîne prototype de MyClass, afin que votre instance MyClass puisse utiliser la méthode Prototype de EventEmitter.
Événement de lancement
En héritant de EventEmitter, MyClass peut lancer des événements comme celui-ci:
La copie de code est la suivante:
Myclass.prototype.somemethod = function () {
this.emit ("événement personnalisé", "argument 1", "argument 2");
};
Dans le code ci-dessus, lorsque la méthode SomeMethond est appelée par l'instance MyClass, un événement appelé "Événement mignon" sera émis. Cet événement émettra également deux chaînes sous forme de données: "Argument 1" et "Argument 2", qui sera transmis en tant que paramètres à l'écouteur de l'événement.
Le client de l'instance MyClass peut écouter l'événement "événement personnalisé" comme ceci:
La copie de code est la suivante:
var myinstance = new myClass ();
MyInstance.on ('Custom Event', fonction (str1, str2) {
Console.log ('a obtenu un événement personnalisé avec les STR1% S et STR2% S!', STR1, STR2);
});
Par exemple, vous pouvez créer une classe de ticker qui émet des événements "Tick" une fois par seconde:
La copie de code est la suivante:
var util = require ('util'),
EventEMitter = require ('Events'). EventEMmitter;
var ticker = function () {
var self = this;
setInterval (function () {
self.emit («tick»);
}, 1000);
};
util.inherits (Ticker, EventEmitter);
Les clients utilisant la classe Ticker peuvent montrer comment utiliser la classe Ticker et écouter les événements "Tick".
La copie de code est la suivante:
var ticker = new ticker ();
ticker.on ("tick", function () {
Console.log ("Tick");
});
résumé
Le mode d'émetteur d'événements est un modèle de réentrance qui peut être utilisé pour découpler l'objet d'émetteur d'événements à partir d'un ensemble de code pour un événement spécifique.
Vous pouvez utiliser event_emitter.on () pour enregistrer les auditeurs pour des types d'événements spécifiques et se désinscrire avec event_emitter.removeListener ().
Vous pouvez également créer votre propre émetteur d'événements en héritant EventEmitter et simplement en utilisant la fonction .emit ().