在 Node Js 和 Express 项目中创建单例 EventEmitter

Creating a Singleton EventEmittor in Nodejs & Express Project

我正在尝试使用 Nodejs eventEmitters 为我的 nodejs/express API 项目创建发布者-订阅者模式。我的用例相当简单:

  1. 我想从项目中的不同位置发出事件。例如,创建新用户时发出事件。
  2. 然后我想要一个地方,我可以在其中收听所有事件并决定采取什么行动。

这将需要 eventEmitter 的单例实例,因为 'emit' 和 'on' 调用应该发生在 'event' 对象的同一实例上。

为了实现它,我的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
}

这就是我的 middleware/controller 函数的样子(我在其中发出事件):

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)
  }
}

而且,这就是我的 事件订阅者 文件的样子:

const eventSubscribers = (req) => {
    const eventEmitter = req.app.get('eventEmitter');

    eventEmitter.on('USER_CREATED', ({ email, name }) => {
        console.log('event fired and captured')
    })
}

使用这个,事件被发出,但事件订阅者没有被触发。我认为我在订阅者中访问 req/app 对象的方式有问题。另外,我得到

TypeError: eventListeners.eventSubscribers is not a function

我的 index.js 文件中有错误。我的问题:

  1. 这是创建 publisher/subscriber 模式的正确方法吗?
  2. 如何访问我的事件订阅者中的 req/app 个对象实例?
  3. 确保在加载应用程序时加载事件订阅者文件的最佳方法是什么?

假设您已正确设置其他所有内容,
我认为你提到的错误的原因

TypeError: eventListeners.eventSubscribers is not a function

是没有函数传递给中间件,即作为中间件,你不应该像这样传递 eventListeners.eventSubscribers

app.use(eventListeners.eventSubscribers);

而不是像这样

app.use(eventListeners.eventSubscribers());

如果我们比较上面的两个表达式,在第二种情况下,express 无法在您调用它时传递请求对象,但此函数调用不会向 express 返回任何内容,即某种 void,但在第一种情况下,因为您将函数对象引用传递给 express,然后它将其作为中间件调用(稍后作为回调并在调用它时将请求对象传递给它)。

或者我认为您不需要使用中间件来使用 EventEmitter,您可以只保留一个由 EventEmitter 组成的全局自定义实例,因为它是 属性 以及您想要收听的所有不同事件,然后在任何你需要的地方使用它们 them.You 可以使用 EventEmitter 作为这个自定义的 属性 通过导入这个自定义模块在你想要的任何模块中发出事件。

这是下面的工作示例

index.js file/entry 文件

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!'))

这是我们使用 EventEmitter 作为 属性 的全局单例自定义实例。

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();

这里我们在请求路由中使用我们的全局 CustomEventEmitter 模块 即 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;