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

时间:2022-04-23 11:12:37

Here is a scenario, I've implemented a loopback remote method which imports some data from REST connector to local postgresql connector.

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

I can do this for a single model

我可以为一个模型做到这一点

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

So the chain does many thing and at the end importCompleted calls the provide cb which is the callback that returns the response to the REST API.

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

But I can't figure how to do this with multiple models and return each result. I tried something like this, it works actually but REST API never receives a result.

但我无法想象如何使用多个模型执行此操作并返回每个结果。我试过类似这样的东西,它确实有效,但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);
};

I'm lost at that point, any ideas?

那时我迷路了,有什么想法吗?

EDIT

编辑

Trying @Otze's answer I tried this also

尝试@ 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);
    });
};

But the result is the same, cb gets called early but the code actually runs in order. I just can't get the result to the response. I think it's never ends so the REST API gets no content after some time.

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

2 个解决方案

#1


0  

Have a look at Q.all or any of the other promise combination functions:

看看Q.all或任何其他承诺组合功能:

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

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

With Q.all you could do somehting like this:

有了Q.all,你可以这样做:

var promises = myModels.map(doAllThePromiseThings);

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

Note that you need to return a promise from doAllThePromiseThings. Since .then returns a promise you can simply do:

请注意,您需要从doAllThePromiseThings返回一个承诺。因为.then返回一个承诺你可以简单地做:

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

instead of

代替

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

#2


0  

I use bluebird library's map method to accomplish such use cases: https://github.com/petkaantonov/bluebird/blob/master/API.md#mapfunction-mapper--object-options---promise

我使用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);
});

#1


0  

Have a look at Q.all or any of the other promise combination functions:

看看Q.all或任何其他承诺组合功能:

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

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

With Q.all you could do somehting like this:

有了Q.all,你可以这样做:

var promises = myModels.map(doAllThePromiseThings);

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

Note that you need to return a promise from doAllThePromiseThings. Since .then returns a promise you can simply do:

请注意,您需要从doAllThePromiseThings返回一个承诺。因为.then返回一个承诺你可以简单地做:

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

instead of

代替

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

#2


0  

I use bluebird library's map method to accomplish such use cases: https://github.com/petkaantonov/bluebird/blob/master/API.md#mapfunction-mapper--object-options---promise

我使用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);
});