回调如何在NodeJS中完全起作用?

时间:2012-09-28 20:37:59

标签: node.js callback express

我有一个带有用户对象的mongob。这是架构:

{
    "_id": {
        "$oid": "50658c835b821298d3000001"
    },
    "email": "admin",
    "password": "admin",
    "id": 1
}

我写了一个简单的演示(只有主要部分):

function findByEmail(email, callback) {
  db.collection("users", function(err, collection) {
      collection.find({}, function(err, users) {
          users.each(function(err, user) {
              if (user) {
                  if (user.email === email) {
                      //for a case, is we found user - return it
                      callback(null, user);
                  }
              }
          });
          //for a case, is we didn't find user - return null
          callback(null, null);
      });
  });
}

测试路线:

app.get('/test',function(req,res){
  findByEmail("admin", function(err, user){
    res.send(user);
  })
})

在推出localhost:3000 / test后我得到了

Error: Can't set headers after they are sent.

如果我评论第callback(null, null);行,我就不会收到此错误。似乎回调工作......两次!怎么会这样?我认为,如果我if (user.email === email) { ... }有效并且callback(null, user);已启动,则函数findbyEmail会将<user>返回到app.get,但回调会工作两次(对于callback(null, null);即使if (user.email === email) { ... }成立也是如此。

3 个答案:

答案 0 :(得分:3)

您在迭代结果后立即调用callback(null, null)。因此,如果您有一些结果 - callback将被调用两次:

  • 一个用于处理结果(将发送输出)
  • ,迭代后第二次。

如果没有结果,您只能致电callback(null, null)

if (!users || users.toArray().length==0) callback(null, null);

答案 1 :(得分:0)

你的回调仍然被执行:

for ( var key in obj ) {
  foo();
}

foo();

为什么你不期望第二个foo()不被调用?

你需要做返回foo();如果你不想继续前进。

答案 2 :(得分:0)

让我们将您传递给collection.find的功能称为outer,将传递给users.each的功能称为inner(我已在代码块中将其标记为下面为了清楚起见)。现在,问题是当你在callback(null, user)中调用inner时,users.each循环继续运行,并且仍将继续测试结果中的所有剩余元素;此外,outer函数仍未完成,并将在callback(null, null)循环完成后调用users.each回调。在找到用户并按照我之前的建议调用return之后,你真的不能只callback(null, user),因为这只会终止users.each循环的单次迭代并继续下一个以及所有剩余的元素;您需要定义一个标志,指示您是否已经找到该记录:

collection.find({}, function outer(err, users) {
    var found = false;
    users.each(function inner(err, user) {
        if (user && !found) {
            if (user.email === email) {
                //for a case, is we found user - return it
                callback(null, user);
                found = true;
            }
        }
    });
    //for a case, is we didn't find user - return null
    if (!found) {
        callback(null, null);
    }
});

另请注意,您可以通过mongo中的电子邮件完全搜索用户记录,并用以下内容替换整个逻辑:

collection.find({ email: email }, function(err, users) {
    callback(null, users.length? users[0]: null);
});