Генератор событий не работает должным образом после первого запроса - PullRequest
0 голосов
/ 28 января 2019

В моем приложении express.js есть базовый контроллер.И я пытаюсь выполнить определенный сервис, который извлекает фиктивные данные после небольшой задержки.Эта служба наследуется от EventEmitter и генерирует событие SUCCESS после получения данных.

Вот мой контроллер:

const express = require('express');
const router = express.Router();
const GetAllUsers = require('../GetAllUsers');
const getAllUsers = new GetAllUsers();

router.get('/', function(req, res, next) {
  getAllUsers
    .on('SUCCESS', (users) => {
      res
        .status(200)
        .json({ users });
    })
    .on('ERROR', next);

  getAllUsers.execute();
});

module.exports = router;

И служба:

const EventEmitter = require('events');

class GetAllUsers extends EventEmitter {
  async execute() {
    const data = [{ id: 1, name: 'user 1' }, { id: 2, name: 'user 2' }];

    try {
      const users = await new Promise(resolve => {
        setTimeout(() => {
          resolve(data);
        }, 1000);
      })

      this.emit('SUCCESS', users);
    } catch (error) {
      this.emit('ERROR', error);
    }
  }
}

module.exports = GetAllUsers;

Проблема в том, что когда я вхожу по пути /users в первый раз, я фактически получаю список пользователей.Но когда я пробую второй и последующие шаги, я получаю следующую ошибку:

Cannot set headers after they are sent to the client
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:471:11)
    at ServerResponse.header (/home/debian/dev/sandbox/emitterTest/node_modules/express/lib/response.js:767:10)
    at ServerResponse.send (/home/debian/dev/sandbox/emitterTest/node_modules/express/lib/response.js:170:12)
    at ServerResponse.json (/home/debian/dev/sandbox/emitterTest/node_modules/express/lib/response.js:267:15)
    at GetAllUsers.getAllUsers.on (/home/debian/dev/sandbox/emitterTest/routes/users.js:12:10)
    at GetAllUsers.emit (events.js:187:15)
    at GetAllUsers.execute (/home/debian/dev/sandbox/emitterTest/GetAllUsers.js:14:12)

Насколько я понимаю, заголовки устанавливаются где-то до того, как я отправлю свой ответ.

И когда япытаясь реализовать мой контроллер без излучателя, все работает нормально:

router.get('/', async function(req, res, next) {
  const data = [{ id: 1, name: 'user 1' }, { id: 2, name: 'user 2' }];

  const users = await new Promise(resolve => {
    setTimeout(() => {
      resolve(data);
    }, 1000);
  })

  res
    .status(200)
    .json({ users });
});

Как решить эту проблему?

1 Ответ

0 голосов
/ 28 января 2019

Это происходит потому, что каждый раз, когда вы делаете запрос, вы запускаете функцию маршрутизатора:

function(req, res, next) {
  getAllUsers 
    .on('SUCCESS', (users) => { //subscribe to event every time
      res
        .status(200)
        .json({ users });
    })
    .on('ERROR', next);

  getAllUsers.execute();
}

Вы подписаны на это событие и запускаете его один раз.В то время, когда вы сделали второй запрос, вы получили 2 подписчика: из предыдущего запроса и из текущего.Затем функция execute() запускает событие.Таким образом, одновременно выполняются 2 функции, и одна из них пытается отправить ответ снова , но это невозможно, поэтому это вызывает ошибку.

Если действительно необходим источник событийВы можете подписаться на событие пожара только один раз, используя функцию getAllUsers.once.

...