Javascript 在每次迭代期间进行迭代并进行异步调用的最佳方法

Javascript 在每次迭代期间进行迭代并进行异步调用的最佳方法,javascript,node.js,asynchronous,Javascript,Node.js,Asynchronous,在我的例子中,如果您必须循环并对存储库或网关进行一系列调用,那么如何异步执行这一操作,即不将异步调用包装在同步for循环中 例如,有什么更好的方法(重构此代码)可以循环一组ID,并像我正在尝试的那样调用下面的find() 目标:我想获取一个id数组,迭代它们,在每次迭代过程中,使用该id调用网关上的find(),以获取该id的对象,然后将其填充到最终数组中,在完成所有操作后返回 我正在使用的内容: (用于承诺) (点击数据库) someModule.js var _gateway = req

在我的例子中,如果您必须循环并对存储库或网关进行一系列调用,那么如何异步执行这一操作,即不将异步调用包装在同步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);
'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);
};
'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;
});
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);
                 });
             };
        });
    }
};
'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);
        });
};
[same code, has not changed]
carModel.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);
'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);
};
'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;
});
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);
                 });
             };
        });
    }
};
'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);
        });
};
[same code, has not changed]
因此,我需要帮助理解如何重构someModule.js中的代码以使其正常工作,以便为每个id调用find(),将找到的每辆车填充到数组中,然后返回数组。carModel代码是异步的。它转到一个物理数据库来执行实际的查询查找

更新#1

好的,在多尝试了几个小时的各种sh**(q.all(),以及大量其他回调代码组合,等等)之后,这里是我在这一点上得到的:

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);
'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);
};
'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;
});
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);
                 });
             };
        });
    }
};
'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);
        });
};
[same code, has not changed]
carModel.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);
'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);
};
'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;
});
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);
                 });
             };
        });
    }
};
'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);
        });
};
[same code, has not changed]
当然,我注意到for循环异步触发了我所有的函数调用,因此当我编写console.I时,它是10,因为for循环已经完成,但正如我们所知,console.log的其余部分在回调完成之后发生

所以我还是不能让它正常工作

当我在附近玩耍的时候,我沿着这条路开始,但它在一堵砖墙处结束:

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);
    });
});
var find=Q.async(函数(carid、cars)
{
var任务=[];
var foundCars=[];
对于(变量i=0;i

每次我都会使用[object promise]for values[I]而不是一辆汽车for values[I]

使用es6中的vanilla
promise
API(并由Bluebird和其他LIB复制),这可能非常容易。首先将ID映射到承诺数组:

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

我不知道Q Promissions库,但这里有一个使用node.js中内置的通用承诺的解决方案。这将并行运行所有请求,然后在收集完所有结果后,运行最终的
。然后()
处理程序,处理所有结果:

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);
});
var\u gateway=require('./数据库/someGateway');
var承诺=[];
对于(var i=0;i

个别promise库(如我所知的Bluebird库)内置了一些功能,可以让您用更少的代码执行此类活动,但我有意将此答案保留为仅使用标准promise功能。

也许可以将
\u gateway.find(carId)
带到for循环之外并存储它<代码>var r=\u gateway.find(results.docs[0].carId)
然后在循环中,说
r=r.Then(_gateway.find.bind(results.docs[i])。然后(…)
,在循环后,调用
r.done(…)
。披露在查看Q文档之前,我没有使用过Q库,看起来您可以使用
Q.all([…])
,其中数组由Q承诺组成。谢谢让我仔细阅读您的评论将其保存在变量中对异步有何作用?学习如何做得好、可靠、可靠,可维护的异步开发是在node.js开发中学习的关键技能。一旦您了解了它,并了解了如何使用Promissions和其他库等工具来帮助您管理它,并了解了要做出的设计选择和要使用的实现工具,就不难了。但是,有一个学习曲线可以让你加快速度。对于地图,它只是一个简单的js map(),它说在文档中获取每个对象,然后返回我们将每个文档映射到的函数的结果,对吗?因为map的工作原理,你最终得到了多个承诺?因此,对于每个文档,运行_gateway.find(doc.carId)promise(函数)我可能最终会使用一个库,但我打赌你可以告诉我更多关于我为什么要使用库的信息(它给了我什么,而不是现成的香草承诺?)是的,这正是map()的工作原理:)至于香草承诺之外的东西,我强烈推荐“co”或者类似的:谢谢,我相信这也行……你也有同样的想法