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