如果你必须在我的情况下循环并对存储库或网关进行一堆调用,我该如何异步地执行此操作意味着不在同步for循环中包装我的异步调用?
例如,更好的方法(重构此代码)循环遍历一组id,并调用find(),就像我试图做的那样?
目标:我想获取一组id,迭代它们,并在每次迭代中,使用id在我的网关上调用find()来获取该id的对象,然后把它塞进一个最终的数组中,当我说完所有的时候我会回来。
我正在使用:
someModule.js
var _gateway = require('./database/someGateway');
var cars = [];
var car;
for (var i = 0; i < results.docs.length; i++){
var carId = results.docs[i].carId;
_gateway.find(carId)
.then(function(data){
console.log('data[0]: ' + data[0].id);
cars.push(data[0]);
})
.done();
}
console.log("cars: " + cars.length); // length here is 0 because my asyn calls weren't done yet
result(cars);
someGateway.js
'use strict';
var Q = require('q');
var _carModel = require('../../models/car');
module.exports = {
models: {
car: _carModel
},
find: _find
};
function _find(carId)
{
return _carModel.find(carId);
};
carModel.js
'use strict';
var Q = require('q');
var pg = require('co-pg')(require('pg'));
var config = require('../../models/database-config');
var car = module.exports = {};
car.find = Q.async(function *(id)
{
var query = 'SELECT id, title, description FROM car WHERE id = ' + id;
var connectionResults = yield pg.connectPromise(config.connection);
var client = connectionResults[0];
var done = connectionResults[1];
var result = yield client.queryPromise(query);
done();
console.log("result.rows[0].id: " + result.rows[0].id);
return result.rows;
});
所以我需要帮助理解如何在someModule.js中重构我的代码以使其正常工作,以便我为每个id调用find(),将每个找到的汽车放入数组中,然后返回数组。 carModel代码是异步的。它会转到物理数据库以执行实际的查询查找。
更新#1
好几个小时后尝试了各种各样的sh **(q.all(),以及大量其他回调代码组合等),这就是我现在所拥有的:< / p>
someModule.js
var _data;
var Q = require('q');
var _solrClient = require('../models/solr/query');
var _solrEndpoint = "q=_text&indent=true&rows=10";
var _postgreSQLGateway = require('./database/postgreSQLGateway');
module.exports = {
data: function(data){
_data = data;
},
find: function (text, result){
if(!searchText){
result(null);
};
_solrClient.query(endpoint, function(results){
var carIds = [];
var cars = [];
var car;
for (var i = 0; i < results.docs.length; i++){
carIds.push(results.docs[i].carId);
}
for (var i = 0; i < carIds.length; i++) {
var car = _postgreSQLGateway.find(carIds[i], function(o){
console.log("i: " + i);
});
};
});
}
};
someGateway.js
'use strict';
var Q = require('q');
var _carModel = require('../../models/postgreSQL/car');
module.exports = {
models: {
car: _carModel
},
find: _find
};
function _find(carId, foundCar)
{
console.log("CALL MADE");
_carModel.find(carId)
.then(function(car){
console.log("car: " + car[0].id);
foundCar(car);
});
};
carModel.js
[same code, has not changed]
当然我注意到for循环触发了我的所有函数调用asyncronously,所以当我console.write i时,它是10,因为for循环完成了但是我们知道,其余的console.logs在回调完成后发生。
所以我仍然无法正常工作......
当我在玩耍的时候,我开始沿着这条路走下去,但它在一堵砖墙上结束了:
var find = Q.async(function(carIds, cars)
{
var tasks = [];
var foundCars = [];
for (var i = 0; i < carIds.length; i++) {
tasks.push(_postgreSQLGateway.find(carIds[' + i + ']));
};
Q.all([tasks.join()]).done(function (values) {
for (var i = 0; i < values.length; i++) {
console.log("VALUES: " + values[0]);
foundCars.push(values[0]);
}
cars(foundCars);
});
});
我每次都以[物品承诺]结束价值[i]而不是汽车价值[i]
答案 0 :(得分:3)
我不知道Q promises库,但这里是使用内置于node.js中的泛型Promise的解决方案。这会并行运行所有请求,然后在收集完所有结果后,它会运行最终的.then()
处理程序并显示所有结果:
var _gateway = require('./database/someGateway');
var promises = [];
for (var i = 0; i < results.docs.length; i++) {
promises.push(_gateway.find(results.docs[i].carId).then(function (data) {
console.log('data[0]: ' + data[0].id);
return data[0];
}));
}
Promise.all(promises).then(function(cars) {
// cars will be an array of results in order
console.log("cars: " + cars.length);
result(cars);
});
个人承诺库(比如我认识的Bluebird)具有内置功能,可让您以更少的代码执行此类活动,但我故意将此答案保留为仅使用标准承诺功能。
答案 1 :(得分:2)
使用es6中的vanilla Promise
API(由Bluebird和其他lib复制)可能非常容易。首先将ID映射到promises数组:
var promises = results.docs.map(function(doc) {
return _gateway.find(doc.carId);
});
然后为聚合结果创建一个承诺:
var allDone = Promise.all(promises);
然后在聚合承诺的done()
回调中,您将获得最终结果数组,其长度和顺序与carId
数组相同:
allDone.then(function(results) {
// do something with "results"
});