Låt oss börja med den allmänna regeln för att använda löften:
Varje funktion som gör något asynkront måste ge ett löfte
Vilka funktioner är det i ditt fall? Det är getPrayerInCat
, forEach
återuppringning och Prayer.find
.
Hm, Prayer.find
returnerar inte ett löfte, och det är en biblioteksfunktion så vi kan inte ändra det. Regel 2 kommer till spel:
Skapa ett omedelbart omslag för varje funktion som inte gör det
I vårt fall är det enkelt med Q:s nodgränssnittshjälpare:
var find = Q.nbind(Prayer.find, Prayer);
Nu har vi bara löften och behöver inte längre några uppskjutningar. Tredje regeln kommer in:
Allt som gör något med ett asynkront resultat går in i en
.then
återuppringning
...och returnerar resultatet. Helvete, det resultatet kan till och med vara ett löfte om "något" var asynkront! Med detta kan vi skriva hela återuppringningsfunktionen:
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 något lite mer komplicerat:en loop. Upprepade anrop av getPrayerCount()
kommer att ge oss flera löften, vars asynkrona uppgifter löper parallellt och löser sig i okänd ordning. Vi vill vänta på dem alla - d.v.s. få ett löfte som löser sig med alla resultat när var och en av uppgifterna är klara.
För så komplicerade uppgifter, försök inte komma på din egen lösning:
Kontrollera API:et för ditt bibliotek
Och där hittar vi Q.all
, som gör just detta. Skriver getPrayerInCat
är en bris nu:
function getPrayerInCat(data) {
var promises = data.map(getPrayerCount); // don't use forEach, we get something back
return Q.all(promises);
// ^^^^^^ Rule 1
}
Om vi behövde göra något med arrayen som Q.all
löser sig, tillämpa bara regel 3.