Ответ 1
Начнем с общего правила использования promises:
Каждая функция, которая делает что-то асинхронную, должна возвращать обещание
Какими функциями они являются в вашем случае? Это getPrayerInCat
, обратный вызов forEach
и Prayer.find
.
Hm, Prayer.find
не возвращает обещание, и это функция библиотеки, поэтому мы не можем ее модифицировать. Правило 2 вступает в игру:
Создайте немедленную оболочку для каждой функции, которая не
В нашем случае это легко с Q node -interfacing helpers:
var find = Q.nbind(Prayer.find, Prayer);
Теперь у нас есть только promises, и больше не нужно никаких отсрочек. Вступает в игру третье правило:
Все, что делает что-то с результатом async, переходит в
.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()
, мы получим несколько promises, чьи асинхронные задачи выполняются параллельно и разрешаются в неизвестном порядке. Мы хотим дождаться их всех, т.е. Получить обещание, которое решает все результаты, когда каждая из задач завершена.
Для таких сложных задач не пытайтесь найти свое решение:
Проверьте 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.