所有操作完成后返回q解决

时间:2015-06-14 02:32:27

标签: node.js mongoose q

我有一个函数,我只想在foreach完成时解决..我使用q和mongoose这是大写的东西所指的,基本上我想首先创建一组项目,然后运行一个foreach完成后的功能。

function createItems() {

  var deferred = Q.defer();

  var itemsArray = [{ 'name' : 'spade' }, { 'name' : 'bucket' } , { 'name' : 'sand'}];

  itemsArray.forEach(function(itemObj) {
    var item = new Item(itemObj); // forces it to use a schema (dont worry)
    Item.findOneAndUpdate({
      url: item.short_name
    }, item, {
      upsert: true
    }, function(err) {
      if (!err) {
        console.log(item.name + ' created.');
        deferred.resolve();
      } else {
        deferred.reject(new Error(err));
      }
    });
  });


  return deferred.promise;
}

createItems()
    .then(function() {
      console.log('All items done.');
    });

所以我希望在控制台上看到类似的内容;

创建了spade项目 铲斗项目已创建 沙子项目创建 所有项目都已完成。

1 个答案:

答案 0 :(得分:3)

快速放弃:您的数组存在语法问题,它包含一个多次尝试写入name的对象。我假设您打算拥有一个对象数组,每个对象都有一个name

基本上,您的方法失败是因为您在第一个实例上解决了您的承诺。您需要一个代表多个异步调用完成的承诺。标准的方法是将 promises数组传递给像Q.all / Bluebird.all / Promise.all这样的库函数。 all函数接受一系列promise并返回一个结果数组的promise。它会在所有承诺解决时解决,或者当任何一个承诺拒绝时拒绝。

function createItems() {

  var promisesForUpdatedDocs = [];

  var itemsArray = [
    { name: 'spade'},
    { name: 'bucket'},
    { name: 'sand'}
  ];

  itemsArray.forEach(function(itemObj) {
    var item = new Item(itemObj);
    var updatedDocPromise = Item.findOneAndUpdate({
      url: item.short_name
    }, item, {
      upsert: true
    }).exec(); // returns an mPromise
    promisesForUpdatedDocs.push(Q(updatedDocPromise)); // using Q to turn the mPromise to a Q promise, and adding it to an array
  });

  return Q.all(promisesForUpdatedDocs); // creates a promise for array of results (from array of promises)
}

createItems()
  .then(function(items) {
    console.log('All items done:', items);
  }).catch(console.log); // never forget to handle errors! Always `return` or `catch` a promise chain.