2015-07-31 3 views
1

Если вам нужно зациклиться и сделать кучу вызовов в репозиторий или шлюз в моем случае, как это сделать, что асинхронно означает не переносить мои асинхронные вызовы внутри синхронного цикла ?Лучший способ итерации и вызова Async во время каждой итерации

Например, что было бы лучшим подходом (перестройкой этого кода), чтобы перебрать набор идентификаторов и сделать вызов find() ниже, как я пытаюсь сделать?

Цель: Я хочу взять массив идентификаторов, перебирать их, и во время каждой итерации, используйте идентификатор для вызова поиска() на моем шлюзе пойти получить объект для этого идентификатора, то запихнуть его в окончательный массив, в который я вернусь, когда все будет сказано и сделано.

Что я использую:

  • q (обещаний)
  • co-pg (поразить базу)

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, чтобы получить, что работать должным образом, так что я делаю вызов find() для каждого идентификатора, набивайте каждый найденный автомобиль в массив, а затем возвращайте массив. Код carModel является асинхронным. Он отправляется в физическую базу данных для выполнения фактического поиска запросов.

UPDATE # 1

Ok после того, как еще пару часов, пытаясь все виды ш ** (q.all(), и тонны других комбинаций кода обратного вызова и т.д.) вот что я есть на данный момент:

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] 

Конечно, я заметил, что для цикла выстреливает все мои вызовы функций асинхронных и поэтому, когда я Console.Write двутавровый, это 10, так как для петли но тогда, как мы знаем, остальные 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); 
    }); 
}); 

я закончил с [объект обещание] каждый раз при значениях [я] вместо автомобиля для value [i]

+0

Возможно, запустите '_gateway.find (carId)' вне цикла for и сохраните его. 'var r = _gateway.find (results.docs [0] .carId);' Тогда в цикле скажем 'r = r.then (_gateway.find.bind (results.docs [i])), затем (. ..) ', а после цикла вызовите' r.done (...) '. * Раскрытие информации Я еще не использовал библиотеку Q * – azz

+1

Просто глядя на Q-документы, похоже, что вы можете использовать 'Q.all ([...])', где массив состоит из Q-обещаний. – azz

+0

Спасибо, позвольте мне пожевать ваши комментарии. – PositiveGuy

ответ

1

Это потенциально очень просто с использованием API-интерфейса vanilla Promise от es6 (и реплицируется Bluebird и другими библиотеками). Первая карта идентификаторов в массив обещаний:

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

спасибо, и ознакомьтесь с моим обновленным кодом – PositiveGuy

+0

для карты, это просто простая js-карта(), в которой говорится, что каждый объект в docs и вернуть результат для функции, по которой мы сопоставляем каждый документ вправо? И поэтому вы получаете множество обещаний из-за того, как работает карта? Поэтому для каждого документа запустите _gateway.find (doc.carId) обещание (функция) – PositiveGuy

+0

Возможно, я, скорее всего, воспользуюсь библиотекой, но я уверен, вы можете рассказать мне больше о том, почему я хочу использовать библиотеку (что делает это дает мне против безоговорочных обещаний ванили?) – PositiveGuy

2

Я не знаю, что Q обещает библиотеку, но вот решение, использующее общий посыл s, встроенный в node.js. Это запускает все запросы параллельно, а затем, когда были собраны все результаты, он запускает окончательный .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) есть функции, встроенные в том, что позволяет делать этот вид активности еще меньше кода, но я намеренно сохранил этот ответ только с использованием стандартных функций обещания.

+0

спасибо, я уверен, что это тоже работает ... у вас такая же идея – PositiveGuy

Смежные вопросы