Maison >interface Web >js tutoriel >Comment créer un émetteur d'événements prioritaires personnalisé dans Node.js

Comment créer un émetteur d'événements prioritaires personnalisé dans Node.js

Susan Sarandon
Susan Sarandonoriginal
2024-12-20 16:05:11998parcourir

How to Create a Custom Priority Event Emitter in Node.js

Installation:

Installation et configuration des bibliothèques

npm i -d @types/node tsx typescript
npx tsc --init

Modifiez tsconfig.json et package.json

// tsconfig.json
{
  "compilerOptions": {
    "target": "es2016",
    "module": "ES6",
    "moduleResolution": "nodenext",
    "allowImportingTsExtensions": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "outDir": "./dist",
    "types": ["node"]
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules"]
}

// package.json
{
  "name": "node-starter",
  "version": "0.0.0",
  "type": "module", // This should be set to "module" for using ES6 modules
  "scripts": {
    "test": "jest"
  },
  "devDependencies": {
    "@types/jest": "^29.5.14",
    "jest": "^29.7.0",
    "typescript": "^5.7.2"
  },
  "dependencies": {
    "@types/node": "^22.10.2",
    "tsx": "^4.19.2"
  }
}

Comprendre EventEmitter dans Node.js

Node.js utilise EventEmitter comme classe fondamentale pour gérer les événements dans la programmation asynchrone. Cette classe vous permet d'enregistrer des auditeurs pour des événements spécifiques et d'émettre ces événements en cas de besoin. Par défaut, EventEmitter traite les événements dans l'ordre dans lequel les écouteurs ont été ajoutés. Cependant, nous pouvons parfois souhaiter donner la priorité à l’exécution de certains auditeurs par rapport à d’autres. C'est là que nous pouvons introduire un système d'événements basé sur les priorités.

Étapes pour créer un émetteur d'événements prioritaire

  1. Héritage de EventEmitter :
    Pour créer un émetteur d'événements personnalisé avec gestion des priorités, nous devons étendre la classe EventEmitter intégrée. Cela nous donne accès à toutes les méthodes intégrées comme on, émettre et supprimerListener.

    import EventEmitter from 'events';
    
    export class PriorityEmitter extends EventEmitter {
      private _listeners: Record<
        string,
        { listener: (...args: any[]) => void; priority: number }[]
      >;
    
      constructor() {
        super();
        this._listeners = {};
      }
    }
    
- `PriorityEmitter` extends `EventEmitter`, so it inherits all of its functionality.
- We introduce a new internal property `_listeners` to store listeners along with their priorities.
  1. Remplacement de la méthode on :
    En remplaçant la méthode on, nous pouvons ajouter une logique personnalisée pour stocker les auditeurs avec leurs priorités et les trier en fonction de leur priorité.

    on(event: string, listener: (...args: any[]) => void, priority = 0) {
      if (!this._listeners[event]) this._listeners[event] = [];
      this._listeners[event].push({ listener, priority });
      this._listeners[event].sort((a, b) => b.priority - a.priority);
      return this;
    }
    
- For production usage, consider using other data structures instead of arrays, which maintain order.
- When a listener is added using `on`, we push the listener and its priority into the `_listeners` array.
- We then sort the listeners in descending order based on the priority. This ensures that higher-priority listeners are executed first.
- The default priority is `0` if not specified.
  1. Remplacer la méthode d'émission :
    La méthode submit déclenche l'événement et exécute les écouteurs. Dans la méthode remplacée, nous traitons d'abord les auditeurs de _listeners en fonction de leur priorité.

    emit(event: string, ...args: any[]) {
      if (this._listeners[event]) {
        for (const { listener } of this._listeners[event]) {
          listener(...args);
        }
      }
      return super.emit(event, ...args);
    }
    
- For the given event, we iterate over the sorted listeners and call each listener.
- After handling the custom priority-based logic, we call the parent class’s `emit` method to ensure the standard behavior is also preserved.
  1. Remplacement de la méthode removeListener :
    La méthode removeListener est remplacée pour garantir que les écouteurs sont correctement supprimés en fonction de leur référence. Puisque nous stockons les auditeurs avec leurs priorités, nous filtrons le bon auditeur.

    removeListener(event: string, listener: (...args: any[]) => void) {
      if (this._listeners[event]) {
        this._listeners[event] = this._listeners[event].filter(
          (stored_listener) => stored_listener.listener !== listener
        );
      }
      super.removeListener(event, listener);
      return this;
    }
    
- We filter the listener array to remove the listener with the exact reference.
- Then we call `super.removeListener` to ensure proper cleanup and avoid memory leaks.

Comment fonctionne le PriorityEmitter

  • Lorsqu'un événement est émis, les auditeurs sont invoqués par ordre de priorité. Plus la priorité est élevée, plus il sera exécuté tôt.
  • Les auditeurs avec une priorité égale sont exécutés dans l'ordre dans lequel ils ont été ajoutés.

Exemple d'utilisation

Voici un exemple pour démontrer comment fonctionne le PriorityEmitter dans la pratique :

const pe = new PriorityEmitter();

// Listener with higher priority
pe.on('greet', (name: string) => {
  console.log(`Hello ${name}!`);
}, 2);

// Listener with lower priority
pe.on('greet', (name: string) => {
  console.log(`Hi, ${name}!`);
}, 1);

// Emitting the event
pe.emit('greet', 'Alice');

Sortie :

npm i -d @types/node tsx typescript
npx tsc --init
  • L'auditeur de priorité 2 (Bonjour Alice !) est appelé en premier.
  • L'auditeur de priorité 1 (Salut Alice !) est appelé ensuite.

Considérations relatives aux performances

  • Choix de la structure des données : Dans cet exemple de base, nous utilisons un tableau pour stocker les écouteurs et les trier à chaque fois qu'un écouteur est ajouté. Cela peut devenir inefficace lorsqu’il y a un grand nombre d’auditeurs. Une meilleure solution pour gérer les priorités dans un environnement où les performances sont critiques serait d'utiliser un tas maximum, qui permet des opérations d'insertion et de suppression efficaces.
  • Utilisation en production : pour les applications de niveau production, envisagez d'utiliser des structures de données plus avancées ou des bibliothèques externes qui fournissent des files d'attente prioritaires pour gérer plus efficacement un grand nombre d'événements.

Code complet

// tsconfig.json
{
  "compilerOptions": {
    "target": "es2016",
    "module": "ES6",
    "moduleResolution": "nodenext",
    "allowImportingTsExtensions": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "outDir": "./dist",
    "types": ["node"]
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules"]
}

// package.json
{
  "name": "node-starter",
  "version": "0.0.0",
  "type": "module", // This should be set to "module" for using ES6 modules
  "scripts": {
    "test": "jest"
  },
  "devDependencies": {
    "@types/jest": "^29.5.14",
    "jest": "^29.7.0",
    "typescript": "^5.7.2"
  },
  "dependencies": {
    "@types/node": "^22.10.2",
    "tsx": "^4.19.2"
  }
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn