Skip to content

Instantly share code, notes, and snippets.

@sylvaindesve
Created January 19, 2022 17:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sylvaindesve/0e5aada4207247e249e97f265e81a052 to your computer and use it in GitHub Desktop.
Save sylvaindesve/0e5aada4207247e249e97f265e81a052 to your computer and use it in GitHub Desktop.
Implémentation de EventEmitter
("use strict");
/**
* Le type des fonctions d'écoute d'un événement.
*
* @typedef Listener
* @type {(...unknown) => void}
*/
/**
* Classe à étendre pour bénéficier d'un mécanisme d'émission et d'écoute
* d'événement.
*
* @example
* ```
* class PersonModel extends EventEmitter {
* #name;
*
* constructor(name) {
* super();
* this.#name = name;
* }
*
* get name() {
* return this.#name;
* }
*
* set name(newName) {
* const oldName = this.name;
* this.#name = newName;
* this.emit("change", "name", newName, oldName, this);
* }
* }
*
* class PersonView {
* #model;
*
* constructor(model) {
* this.#model = model;
* model.on("change", (attribute, newValue, oldValue, model) => {
* console.log(
* `attribute ${attribute} has changed from ${oldValue} to ${newValue}`
* );
* this.render();
* });
* }
*
* render() {
* // Fonction de rendu
* }
* }
* ```
*/
export class EventEmitter {
constructor() {
/**
* Dictionnaire des écouteurs d'événement par nom d'événement.
*
* @type {{[eventName: string]: Listener[]}}
*/
this.listeners = {};
}
/**
* Ajouter un écouteur pour l'événement indiqué.
*
* @param {string} eventName Le nom de l'événement
* @param {Listener} listener La fonction a appeler lorsque l'événement survient
* @returns {() => void} Une fonction permettant de retirer l'écoute
*/
on(eventName, listener) {
if (typeof this.listeners[eventName] !== "object") {
this.listeners[eventName] = [];
}
this.listeners[eventName].push(listener);
return () => this.removeListener(eventName, listener);
}
/**
* Retire une fonction d'écoute pour l'événement indiqué.
*
* @param {string} eventName Le nom de l'événement
* @param {Listener} listener La fonction d'écoute à retirer
*/
removeListener(eventName, listener) {
if (typeof this.listeners[eventName] === "object") {
const idx = this.listeners[eventName].indexOf(listener);
if (idx > -1) {
this.listeners[eventName].splice(idx, 1);
}
}
}
/**
* Emet un évenement en déclenchant toutes les fonctions d'écoute rattaché
* à cet événement.
*
* @param {string} eventName Le nom de l'événement
* @param {...unknown} args Les arguments à passer aux fonctions d'écoute
*/
emit(eventName, ...args) {
if (typeof this.listeners[eventName] === "object") {
this.listeners[eventName].forEach((listener) =>
listener.apply(this, args)
);
}
}
/**
* Ajoute un écouteur qui ne sera déclenché que sur la prochaine émission de
* l'événement en question puis retiré.
*
* @param {string} eventName Le nom de l'événement
* @param {Listener} listener La fonction d'écoute
*/
once(eventName, listener) {
const remove = this.on(eventName, (...args) => {
remove();
listener.apply(this, args);
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment