EventEmitter 触发一次,之后请求挂起

EventEmiter Fire Once, Request Pends After

我正在用 express 尝试在 nodejs 上尝试在这个平台上制作我的第一个应用程序。在图像上的这段代码中,我来自 post 请求,我正在尝试检查发送给我的 userData 是否已经注册。如果不是,它将注册用户。为了最小化回调,我将使用事件来告诉我调用的函数是否完成。在这种情况下,如果图像右侧的 checkUser 函数 属性,如果 db 找到了用户,它将发出左侧写的 userAuthenticated 事件。如果不是,它将写入用户并发出 userRegistered 事件。

问题是有时有效,有时无效。这是我第一次在节点上编写异步函数,我对它的功能感到困惑。

问题是您没有在发送响应后删除事件处理程序。 on() 保留事件处理程序,直到它们被明确删除。因此,对于每个连接,都会添加新的事件处理程序,但不会删除。

即使您使用 .once() 而不是 .on(),您仍然需要删除未触发的其他事件的处理程序。

恕我直言,您最好只使用单个回调,而不是使用 EventEmitter 使事情复杂化。例如:

models/authenticate.js:

// ...

exports.checkUser = function(data, cb) {
  UsersDB.findOne({ fbid: data.id }, function(err, doc) {
    if (err)
      return cb(err);
    if (doc === null)
      insertUser(data, cb);
    else
      cb(null, 'Authenticated', doc);
  });
};
var insertUser = exports.insertUser = function(data, cb) {
  var insertData = {
    fbid: data.id
    first_name: data.first_name
    last_name: data.last_name,
    email: data.email,
    created_at: new Date()
  };
  UsersDB.insert(insertData, function(err, doc) {
    if (err)
      return cb(err);
    cb(null, 'Registered', doc);
  });
};

controllers/authenticate.js:

// ...

model.authenticate(req.body, function(err, action, data) {
  if (err)
    return res.json({ error: err });
  res.json({ action: action, userData: data });
});

此外,您可以简化 "check and insert" 逻辑以使用 MongoDB 的 "upsert" 功能,该功能将为您执行这两个步骤,而不是进行两个单独的数据库调用。要了解如何执行此操作,请查看 this SO answer.