Нека започнем с общото правило за използване на обещания:
Всяка функция, която прави нещо асинхронно, трябва да върне обещание
Кои са тези функции във вашия случай? Това е 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.