在每次迭代期间迭代和调用Async的最佳方法

如果你不得不循环,并在我的情况下一堆调用存储库或网关,我该怎么做asynchronous意味着不包裹我的asynchronous调用内循环同步?

例如,什么是更好的方法(重构此代码)来循环一组ID,并调用find()如下我想要做的?

目标 :我想要一个ID数组,迭代它们,并且在每次迭代中,使用ID在我的网关上调用find()来获取该ID的对象,然后将其填充到最终数组中,当所有的说话和完成之后,我们会回来。

我在用什么

  • q (承诺)
  • 合伙 (打数据库)

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(),将每个find的汽车放到数组中,然后返回该数组。 carModel代码是asynchronous的。 它出到一个物理数据库来执行实际的查询查询。

更新#1

好几个小时后,尝试各种各样的sh **(q.all(),和其他吨的callback代码组合等),这里是我在这一点上:

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循环会asynchronous触发我所有的函数调用,所以当我console.write i时,它是10,因为for循环已经完成,但是正如我们所知,其余的console.logs在callback完成。

所以我仍然无法得到这个工作的权利…

当我在附近玩耍的时候,我开始走下了这条路,但是却在一堵砖墙上结束了:

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

我最终以[对象承诺]的价值观[我]而不是汽车价值[我]

从es6的香草Promise API(由Bluebird和其他库复制),这可能非常容易。 首先将ID映射到承诺数组:

 var promises = results.docs.map(function(doc) { return _gateway.find(doc.carId); }); 

然后为汇总结果创build一个承诺:

 var allDone = Promise.all(promises); 

然后在集合promise的done()callback中,您将获得最终的数组结果,其长度和顺序与carId数组相同:

 allDone.then(function(results) { // do something with "results" }); 

我不知道Q promise库,但是这里有一个使用node.js中的通用Promise的解决scheme。 这将并行运行所有请求,然后在收集完所有结果后,运行包含所有结果的最终.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); }); 

个人承诺库(就像我认识的蓝鸟)有内置的function,可以让你在更less的代码中完成这种活动,但是我有意使这个答案只使用标准承诺function。