Проблема с возвратом данных, полученных из запросов к БД, вызываемых в цикле
Я сделал несколько запросов mongoDB в цикле. и я хочу отправить все результаты в виде одного массива данных. Но когда я просто использую return для отправки данных, он просто возвращает undefined и не ждет результатов всех запросов БД. Я также пытался использовать q.moulde, но та же проблема.
Код:
var getPrayerInCat = function(data){
var result ;
var finalData = [];
if(data.length >0){
data.forEach(function(data2){
var id= data2.id;
Prayer.find({prayerCat:id},function(err,prayer){
var deferred = Q.defer()
if (err) { // ...
console.log('An error has occurred');
// res.send(err);
result= finalData = err
} else {
if(!prayer){
// console.log(data2.id+'--0');
data2.prayersCount = 0;
result = deferred.resolve(finalData.push(data2))
} else {
// console.log(data2.id+'--'+prayer.length);
data2.prayersCount = prayer.length;
// console.log(prayer)
result = deferred.resolve(finalData.push(data2))
} // else for data forward
}
deferred.promise;
})
// deferred.resolve(finalData);
})
/*if(finalData.length > 0) { return finalData;}*/
}
}
finalData возвращается неопределенным.
1 ответ
Давайте начнем с общего правила использования обещаний:
Каждая функция, которая делает что-то асинхронное, должна возвращать обещание
Какие функции это в вашем случае? Это getPrayerInCat
, forEach
обратный вызов и Prayer.find
,
Хм, Prayer.find
не возвращает обещание, и это библиотечная функция, поэтому мы не можем ее изменить. Правило 2 вступает в игру:
Создать непосредственную оболочку для каждой функции, которая не
В нашем случае это легко с помощью помощников по взаимодействию узлов Q:
var find = Q.nbind(Prayer.find, Prayer);
Теперь у нас есть только обещания, и нам больше не нужны отсрочки. Третье правило вступает в игру:
Все, что делает что-то с асинхронным результатом, переходит в
.then
Перезвоните
... и возвращает результат. Черт, этот результат может быть даже обещанием, если "что-то" было асинхронным! С этим мы можем написать полную функцию обратного вызова:
function getPrayerCount(data2) {
var id = data2.id;
return find({prayerCat:id})
// ^^^^^^ Rule 1
.then(function(prayer) {
// ^^^^^ Rule 3
if (!prayer)
data2.prayersCount = 0;
else
data2.prayersCount = prayer.length;
return data2;
// ^^^^^^ Rule 3b
});
}
Теперь у нас есть кое-что более сложное: цикл. Неоднократно звонилgetPrayerCount()
мы получим несколько обещаний, чьи асинхронные задачи выполняются параллельно и разрешаются в неизвестном порядке. Мы хотим дождаться их всех - то есть получить обещание, которое разрешается со всеми результатами, когда каждая из задач завершена.
Для таких сложных задач не пытайтесь придумать свое собственное решение:
Проверьте API вашей библиотеки
И там мы находимQ.all
, который делает именно это. Пишу getPrayerInCat
сейчас ветер:
function getPrayerInCat(data) {
var promises = data.map(getPrayerCount); // don't use forEach, we get something back
return Q.all(promises);
// ^^^^^^ Rule 1
}
Если бы нам нужно было что-то сделать с массивом, Q.all
решает, просто примените правило 3.