用Q链接多个链式承诺(环回应用程序)

时间:2015-09-30 22:04:44

标签: node.js rest q loopbackjs

这是一个场景,我实现了一个环回远程方法,它将一些数据从REST连接器导入到本地postgresql连接器。

我可以为单个模型执行此操作

var importData = function (model, cb) {

    migrateModel(model, cb)
    .then(findImportInfo)
    .then(fetchRemoteData)
    .then(processFetchedData)
    .then(updateImportInfo)
    .then(countLocalData)
    .then(importCompleted)
    .catch(function (err) {
      importFailed(err, cb);
    })
    .done(function () {
      console.log('done');
    });
};

所以链做了很多事情,最后importCompleted调用了提供cb,这是一个返回REST API响应的回调。

但我无法想象如何使用多个模型执行此操作并返回每个结果。我尝试过类似的东西,它实际上有效,但REST API永远不会收到结果。

var importDataAll = function (app, cb) {
  var models = app.models();
  var deferred = Q.defer();
  var promises = [];
  var results = [];

  function doCallback() {
    cb(null, results);
  }

  models.forEach(function (model) {
    if (typeof model.importData === 'function') {
      migrateModel(model, model.definition.name, null)
        .then(findImportInfo)
        .then(fetchRemoteData)
        .then(processFetchedData)
        .then(updateImportInfo)
        .then(countLocalData)
        .then(function (prevResult) {
          var deferred = Q.defer();
          var remoteCount = prevResult.dataCount;
          var localCount = prevResult.recordCount;
          var result =
          {
            'time': new Date(),
            'remoteCount': remoteCount,
            'localCount': localCount,
            'started': prevResult.started,
            'completed': new Date()
          }
          results.push(result);
          deferred.resolve(result);
          return deferred.promise;
        })
        .catch(function (err) {
          promises.reject(err);
        })
    }
  });
  return Q.allSettled(promises).then(doCallback);
};

我在那时失去了任何想法?

修改

尝试@ Otze的答案我也试过了

var importDataAll = function (app, cb) {
  var models = app.models().filter(function (element, index, array) {
    return typeof element.importData === 'function';
  });
  var promises = models.map(function (model) {
    migrateModel(model, model.definition.name, null)
      .then(findImportInfo)
      .then(fetchRemoteData)
      .then(processFetchedData)
      .then(updateImportInfo)
      .then(countLocalData)
      .then(importResult)
      .catch(function (err) {
        promises.reject(err);
      })
  });

  Q.all(promises)
    .then(function (resolvedPromises) {          
      cb(null, results);
    });
};

但结果是一样的,cb被提前调用但代码实际上是按顺序运行的。我只是无法得到响应的结果。我认为它永远不会结束,所以REST API在一段时间后就没有内容了。

2 个答案:

答案 0 :(得分:0)

查看Q.all或任何其他承诺组合函数:

http://documentup.com/kriskowal/q/#combination

使用Q.all你可以这样做:

var promises = myModels.map(doAllThePromiseThings);

Q.all(promises)
  .then(function(resolvedPromises) {
    doStuff();
  });

请注意,您需要从doAllThePromiseThings返回承诺。 由于.then会返回一个承诺,您只需执行以下操作:

 .then(function (prevResult) {
   return {
     'time': new Date(),
     'remoteCount': prevResult.dataCount,
     'localCount': prevResult.recordCount,
     'started': prevResult.started,
     'completed': new Date()
   };
 })

而不是

.then(function (prevResult) {
  var deferred = Q.defer();
  var remoteCount = prevResult.dataCount;
  var localCount = prevResult.recordCount;
  var result =
  {
    'time': new Date(),
    'remoteCount': remoteCount,
    'localCount': localCount,
    'started': prevResult.started,
    'completed': new Date()
  }
  results.push(result);
  deferred.resolve(result);
  return deferred.promise;
})

答案 1 :(得分:0)

我使用bluebird库的map方法来完成此类用例: https://github.com/petkaantonov/bluebird/blob/master/API.md#mapfunction-mapper--object-options---promise

var Promise = require('bluebird');

var importDataAll = function (app, cb) {  
  var models = app.models().filter(function (element, index, array) {
    return typeof element.importData === 'function';
  });

Promise.map(
  models,
  function(model) {
    return migrateModel(model, model.definition.name, null) // don't want to break the promise chain
      .then(findImportInfo)
      .then(fetchRemoteData)
      .then(processFetchedData)
      .then(updateImportInfo)
      .then(countLocalData)
      .then(importResult)
      .then(function(){
        ...
        return Promise.resolve(); // don't want to break the promise chain
      });
  },
  {concurrency: 1}
)
.then(function () {
  debug('finished working on all the models one-by-one');
  cb(null);
})
.catch(function (err) {
  cb(err);
});