【问题标题】:How does callback exactly work in NodeJS?回调在 NodeJS 中究竟是如何工作的?
【发布时间】:2012-09-28 20:37:59
【问题描述】:

我有一个带有用户对象的 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,但即使if (user.email === email) { ... } 为真,回调也会工作两次(也适用于callback(null, null);)。

【问题讨论】:

  • 那么,什么会阻止callback(null, null) 被调用?您在迭代 users 数组后立即调用它,这是无条件发生的。
  • 又一个回调!回调(空,用户); - 如果我们找到用户,回调(空,用户);被调用,并将执行定向到 app.get。这就像一个返回/休息。或不? o_O
  • 不,回调是函数。当你调用一个函数时,好吧,你调用了一个函数。之后你的执行将继续,就像你调用一个函数之后一样。
  • 嗯,我以错误的方式考虑了回调。那么,您如何建议我直接执行 app.get?与“返回”?还是使用'break'?
  • 尝试使用“return callback(null, user);”仍然得到错误:发送后无法设置标题。

标签: node.js callback express


【解决方案1】:

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

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

如果没有结果,您应该只致电callback(null, null)...

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

【讨论】:

  • 您的解决方案有效,谢谢!但是我真的不明白为什么简单的返回不起作用并给我错误:发送后无法设置标题。 ?
  • 或者返回也不会将执行路由到 app.get 我应该手动 break() 吗?
  • @IlyaRusanen,好吧,如果你在callback前面加上return,它会起作用,没有它会继续执行,回调无法控制被调用者的执行流程......
  • 您最后一次编辑返回仍然给我同样的错误。但是 if (!users || users.toArray().length==0) callback(null, null);解决方案有效。似乎 return 不会破坏函数
  • @IlyaRusanen,哦,我错过了第一次回调更深一层,所以return 在这里也没有多大帮助,抱歉没有引导那个...
【解决方案2】:

你的回调仍然被执行:

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

foo();

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

你需要做 return foo();如果你不想继续。

【讨论】:

    【解决方案3】:

    让我们将传递给collection.find 的函数称为outer,将传递给users.each 的函数称为inner(为了清楚起见,我在下面的代码块中将它们标记为这样)。现在,问题是当您在inner 中调用callback(null, user) 时,users.each 循环继续运行,并且仍将继续测试结果中的所有剩余元素;此外,outer 函数仍未完成,将在 users.each 循环完成后调用您的 callback(null, null) 回调。正如我之前建议的那样,在找到用户并调用 callback(null, user) 之后,你不能真的只是 return,因为这只会终止 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);
    });
    

    【讨论】:

      猜你喜欢
      • 2017-01-17
      • 2023-04-01
      • 2011-06-26
      • 2021-08-15
      • 2012-06-08
      • 2011-10-11
      • 2013-07-05
      • 1970-01-01
      相关资源
      最近更新 更多