Lad os starte med den generelle regel for brug af løfter:
Hver funktion, der gør noget asynkront, skal returnere et løfte
Hvilke funktioner er det i dit tilfælde? Det er getPrayerInCat
, forEach
tilbagekald og Prayer.find
.
Hm, Prayer.find
returnerer ikke et løfte, og det er en biblioteksfunktion, så vi kan ikke ændre det. Regel 2 kommer i spil:
Opret en øjeblikkelig indpakning for hver funktion, der ikke gør det
I vores tilfælde er det nemt med Q's node-interface-hjælpere:
var find = Q.nbind(Prayer.find, Prayer);
Nu har vi kun løfter omkring os, og har ikke længere brug for udsættelser. Tredje regel kommer i spil:
Alt, der gør noget med et asynkront resultat, går ind i en .then
tilbagekald
…og returnerer resultatet. For helvede, det resultat kan endda være et løfte, hvis "noget" var asynkront! Med dette kan vi skrive hele tilbagekaldsfunktionen:
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
});
}
Nu har vi noget lidt mere kompliceret:en løkke. Gentagne gange kalder getPrayerCount()
vil give os flere løfter, hvis asynkrone opgaver kører parallelt og løses i ukendt rækkefølge. Vi vil gerne vente på dem alle - dvs. få et løfte, der løser sig med alle resultater, når hver af opgaverne er færdige.
For så komplicerede opgaver, prøv ikke at komme med din egen løsning:
Tjek dit biblioteks API
Og der finder vi Q.all
, som gør præcis dette. Skriver getPrayerInCat
er en leg nu:
function getPrayerInCat(data) {
var promises = data.map(getPrayerCount); // don't use forEach, we get something back
return Q.all(promises);
// ^^^^^^ Rule 1
}
Hvis vi skulle gøre noget med arrayet, så Q.all
løser, skal du blot anvende regel 3.