在nodejs(asynchronous)循环和callback中寻找适当的模式

我已经阅读了几篇文章和文章,但是我不太明白。

我在Mongoose模型中有一段代码,主要负责邀请人们参与项目。 鉴于一些被邀请者,我期待看看他们是否在数据库中,如果没有,我会继续创build它们并更新被邀请者列表中的ID。

jslint抱怨循环,我正在努力与callback(和正确的总体模式,当你有一个循环,与数据库保存callback。显然我想要发生的是循环完全完成,任何新用户都添加到数据库,ID是在原始哈希(受邀者)更新,然后callback发生。

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); }); }; 

这里有几个问题:

  1. 你正在for循环中声明局部variables。 这是因为JavaScript有function范围,而不是块范围(variables提升),所以不鼓励。

  2. 您需要一些方法将您为保存的每个用户所做的asynchronous更改同步到数据库,即等待循环完成。

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

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

然后调用invitees.map(processUser)

2.问题更难:我build议你使用一个提供asynchronous支持的库,比如Q.

要做到这一点,请让processUser函数返回一个在完成时解决的Q promise,然后使用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); }); };