【问题标题】:Looking for proper pattern in looping and callbacks in nodejs (async)在nodejs(异步)中寻找循环和回调的正确模式
【发布时间】:2014-11-22 12:43:08
【问题描述】:

我已经阅读了几篇关于此的帖子和文章,但我不太明白。

我的 Mongoose 模型中有一段代码,它基本上负责邀请人们加入一个项目。给定一些受邀者,我会查看他们是否在数据库中,如果没有,我会继续创建它们并更新受邀者列表中的 id。

jslint 抱怨循环,我正在努力处理回调(以及正确的整体模式,当你有一个循环保存带有回调的数据库时。显然我想要发生的是循环完全完成,任何新用户被添加到数据库中,id 是原始哈希(被邀请者)中的更新,然后回调发生。

ProjectSchema.methods.invite = function invite(invitees, callback) {
  var User = mongoose.model('User');
  var emails = _.pluck(invitees, 'email');
  // loop through invited hash to see if we already have those users in the db
  User.find({ 'email': { $in: emails}}, function (err, users) {
    for (var invited = 0; invited < invitees.length; invited++) {
      var found = false;
      // logic here to see if they are already users using the users param
      if (found) {
        // they are already in the db so do unrelated things.
      } else {
        // create new user
        var User = mongoose.model('User');
        var newUser = // set up new user here

        newUser.save(somecallback?);
        // update invitees list with id
      }
    }
    callback(err, invitees);
  });
};

【问题讨论】:

    标签: javascript node.js asynchronous callback mongoose


    【解决方案1】:

    这里有几个问题:

    1. 您在 for 循环中声明局部变量。不鼓励这样做,因为 JavaScript 具有函数作用域,而不是块作用域(变量提升)。

    2. 您需要某种方式来同步您为保存到数据库的每个用户所做的异步更改,即“等待”循环完成。

    对于1.,我建议你使用Array.map,即声明一个函数

    function processUser (invited) {
      // essentially the body of your for loop
    }
    

    然后拨打invitees.map(processUser)

    2. 问题更难:我建议你使用提供异步支持的库,例如 Q

    为此,请让processUser 函数返回一个在完成后解析的 Q 承诺,然后使用Q.all 进行同步。即类似:

    Q.all(invitees.map(processUser))
      .then(function (completions) {callback(null,invitees);},
            function (err) {callback(err,null);});
    

    总结:

    // import Q
    var Q = require('q');
    
    // ...
    
    ProjectSchema.methods.invite = function invite(invitees, callback) {
    
      var User = mongoose.model('User');
      var emails = _.pluck(invitees, 'email');
      // loop through invited hash to see if we already have those users in the db
    
      function processUser (invited) {
        var deferredCompletion = Q.defer();
    
        var found = false;
        // logic here to see if they are already users using the users param
        if (found) {
          // they are already in the db so do unrelated things.
          // ...
          deferredCompletion.resolve(true); // resolve with some dummy value
        } else {
          // create new user
          var newUser = // set up new user here
    
            newUser.save(function (err, user){
              if (err) {
                deferredCompletion.reject(err);
              } else {
                // update invitees list with id
                // ...
                deferredCompletion.resolve(true);
              }
            });
        }
        return deferredCompletion.promise;
      }
    
      Q.all(invitees.map(processUser))
        .then(function (completions) {
          callback(null,invitees);
        }, function (err) {
          callback(err,null);
        });
    };
    

    【讨论】:

    • 或者,您可以使用async.mapasync.mapLimit。如果您要处理大量用户并且不想使数据库过载,则后者很有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-29
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 2011-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多