Zacznijmy od ogólnej zasady korzystania z obietnic:
Każda funkcja, która robi coś asynchronicznego, musi zwrócić obietnicę
Jakie to funkcje w Twoim przypadku? To jest getPrayerInCat
, forEach
wywołanie zwrotne i Prayer.find
.
Hm, Prayer.find
nie zwraca obietnicy i jest funkcją biblioteczną, więc nie możemy jej modyfikować. W grę wchodzi zasada 2:
Utwórz natychmiastowe opakowanie dla każdej funkcji, która tego nie robi
W naszym przypadku jest to łatwe dzięki pomocnikom Q obsługującym węzły:
var find = Q.nbind(Prayer.find, Prayer);
Teraz mamy tylko obietnice i nie potrzebujemy już żadnych odroczeń. W grę wchodzi trzecia zasada:
Wszystko, co robi coś z wynikiem asynchronicznym, trafia do .then
oddzwonienie
…i zwraca wynik. Do diabła, ten wynik może być nawet obietnicą, jeśli „coś” było asynchroniczne! Dzięki temu możemy napisać kompletną funkcję zwrotną:
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
});
}
Teraz mamy coś bardziej skomplikowanego:pętlę. Wielokrotne wywoływanie getPrayerCount()
da nam wiele obietnic, których asynchroniczne zadania działają równolegle i są rozwiązywane w nieznanej kolejności. Chcemy poczekać na wszystkie z nich - tj. uzyskać obietnicę, która rozwiąże się ze wszystkimi wynikami po zakończeniu każdego z zadań.
W przypadku tak skomplikowanych zadań nie próbuj wymyślać własnego rozwiązania:
Sprawdź interfejs API swojej biblioteki
I tam znajdujemy Q.all
, który dokładnie to robi. Pisanie getPrayerInCat
jest teraz bardzo proste:
function getPrayerInCat(data) {
var promises = data.map(getPrayerCount); // don't use forEach, we get something back
return Q.all(promises);
// ^^^^^^ Rule 1
}
Jeśli musielibyśmy coś zrobić z tablicą, która Q.all
postanawia, po prostu zastosuj Regułę 3.