Estoy tratando de crear un patrón de editor-suscriptor con eventEmitters de Nodejs para mi proyecto API de nodejs/express. Mi caso de uso es bastante simple:
Esto requerirá una instancia singleton de eventEmitter porque las llamadas 'emit' y 'on' deben ocurrir en la misma instancia del objeto 'event'.
Para lograrlo, así es como se ve mi index.js :
const express = require('express') const app = express() const bodyParser = require('body-parser') const routes = require('./api/routes') const EventEmitter = require("events"); const eventEmitter = new EventEmitter(); const eventListeners = require('../src/subscribers/events'); //const eventSubs = new eventListeners(); app.use(eventListeners.eventSubscribers()); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.set('eventEmitter', eventEmitter); app.get('/', (req, res) => res.send('App is working')) app.use('/api', routes) app.listen(3000, () => console.log('Example app listening on port 3000!')) module.exports = { app }Así es como se ve mi función de middleware/controlador (donde estoy emitiendo un evento):
const createUser = async (req, res, next) => { var user = req.body try { console.log('in controller'); await newUser(user) console.log(req.app.get('eventEmitter')); req.app.get('eventEmitter').emit('USER_CREATED', {email: user.email, name: user.name}) res.status(200).send({success: true}); next() } catch(e) { console.log(e.message) res.sendStatus(500) && next(e) } }Y así es como se ve mi archivo de suscriptor de eventos :
const eventSubscribers = (req) => { const eventEmitter = req.app.get('eventEmitter'); eventEmitter.on('USER_CREATED', ({ email, name }) => { console.log('event fired and captured') }) }Con esto, el evento se emite, pero el suscriptor del evento no se activa. Creo que hay algún problema con la forma en que accedo a los objetos de solicitud/aplicación en mi suscriptor. Además, estoy recibiendo
TypeError: eventListeners.eventSubscribers is not a functionerror en mi archivo index.js. Preguntas que tengo:
Suponiendo que todo lo demás esté configurado correctamente por usted,
Creo que la causa del error que mencionas
TypeError: eventListeners.eventSubscribers is not a functiones que no se pasa ninguna función al middleware, es decir, como un middleware, ¿no debería simplemente pasar eventListeners.eventSubscribers de esta manera?
app.use(eventListeners.eventSubscribers);en vez de así
app.use(eventListeners.eventSubscribers());Si comparamos las dos expresiones anteriores, express no puede pasar el objeto de solicitud en el segundo caso, ya que lo está llamando, pero esta llamada de función no devuelve nada al express, es decir, un tipo de vacío, pero en el primer caso desde que pasó el objeto de función referencia a express, luego lo llama como middleware (como una devolución de llamada más tarde y pasa el objeto de solicitud mientras lo llama).
Alternativamente, creo que no necesita usar middleware para usar EventEmitter, puede mantener una única instancia personalizada global que consiste en EventEmitter como su propiedad y todos los eventos diferentes que desea escuchar, y luego simplemente usarlos donde los necesite .Puede usar EventEmitter como una propiedad de este personalizado para emitir eventos en cualquier módulo que desee importando este módulo personalizado allí.
Este es el ejemplo de trabajo a continuación
archivo index.js/archivo de entrada
const express = require('express') const app = express() const bodyParser = require('body-parser') const routes = require("./userRoute"); //const eventSubs = new eventListeners(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.get('/', (req, res) => res.send('App is working')) app.use('/api', routes); app.listen(3000, () => console.log('Example app listening on port 3000!'))Esta es nuestra instancia personalizada de singleton global que utiliza EventEmitter como propiedad.
const { EventEmitter } = require("events"); class CustomEventEmitter { eventEmitter; constructor() { this.eventEmitter = new EventEmitter(); this.initialize(); } getEventEmitter() { return this.eventEmitter; } initialize() { this.eventEmitter.on('USER_CREATED', ({ email, name }) => { console.log('event fired and captured with data', email, name); }); } } module.exports = new CustomEventEmitter();y aquí usamos nuestro módulo global CustomEventEmitter en nuestras rutas de solicitud, es decir, userRoute.js
const router = require("express").Router(); const customEventEmitter = require("./CustomEventEmitter"); const createUser = async (req, res, next) => { var user = req.body try { console.log('in controller'); // await newUser(user) customEventEmitter.getEventEmitter().emit('USER_CREATED', { email: user.email, name: user.name }) res.status(200).send({ success: true }); next() } catch (e) { console.log(e.message) res.sendStatus(500) && next(e) } } router.post("/createUser", createUser) module.exports = router;