Node.js / Sails.js - Function in forEach loop

2019-08-09 19:49发布

I'm trying to get the following simplified code to finish and then move on synchronously:

factors.forEach(function(factor, index){
  Factor.findOrCreate({function_name: factor}).exec(function(){
    sails.log('success');
  })
});

How do I do it?


So far I've tried:

  • Putting lines 2-4 in a separate function and calling that from inside the loop
  • Using the async.js async.series() call

But while it will execute the calls (print 'success'), it'll find or create a Factor in the DB very infrequently, so it has something to do with the asynchronous nature of the code.

  • Using promises to wait until all findOrCreate() calls return, then continuing

    var promises = [];
    factors.forEach(function(factor, index){
      promises.push(Factor.findOrCreate({function_name: factor}));
    });
    Q.all(promises).then(function(){
      sails.log('success');
    });
    

I've tried a few versions of this one, but I still can't get it to print 'success' - This seems like the right way to do it, but I'm not quite sure what's wrong.

3条回答
闹够了就滚
2楼-- · 2019-08-09 20:20

You need to use something like Q, promises. But in a proper asyncronous way.

var cb = function(factor) {
  var deferred = Q.defer();
  Factor.findOrCreate({function_name: factor})
    .exec(function(err, factorObj) {
      if(err) deferred.reject(err);
      deferred.resolve(factorObj);
    });
  return deferred.promise;
};

var promises = [];
Factor.forEach(function(f) {
  promises.push(cb(f));
});

Q.all(promises)
  .then(function() { // You can get the params too.
    console.log('WE ARE THE CHAMPIONS!!');
  })
  .fail(function() { // You can get the error params too.
    console.log('WE LOOSE');
  });

Hope it helps! Its only an example, Its been a few months since I stop using NodeJS and SailsJS (unfortunately).

查看更多
对你真心纯属浪费
3楼-- · 2019-08-09 20:29

There is a simple way of doing this using the async.js library forEachOf method.

Ex :

var async = require('async');
var promises = [];
async.forEachOf(factors,function(factor, key, callback){
  Factor.findOrCreate({function_name: factor}).exec(function(result,err){
    if (err) {
      callback(err);
    } else {
      promises.push(result);
      callback();
    }
  });
}, function(err){
  if (err) {
    console.log("Error: "+err);
  } else {
    console.log(promises);
  }
});
查看更多
不美不萌又怎样
4楼-- · 2019-08-09 20:35

A simple method of doing this without using async or promises would be to manually keep track of how many records have been processed:

var ctr = 0;
factors.forEach(function(factor, index){
    Factor.findOrCreate({function_name: factor}).exec(function(err, factorObj){
        if (err) errorHandler(err);
        ctr ++;
        if (ctr === factors.length) {
            successCallback();
        }
    });
});

successCallback() will be called only after all Factor objects have been created.

Update

Alternatively, you could try this to avoid looping altogether:

Factor.findOrCreate(factors).exec(function(err, factorObjArray){
    callback(err, factorObjArray);
});
查看更多
登录 后发表回答