Laten we beginnen met de algemene regel voor het gebruik van beloften:
Elke functie die iets asynchroon doet, moet een belofte teruggeven
Welke functies zijn dit in jouw geval? Het is getPrayerInCat
, de forEach
terugbellen, en Prayer.find
.
Hmm, Prayer.find
geeft geen belofte terug en het is een bibliotheekfunctie, dus we kunnen het niet wijzigen. Regel 2 komt in het spel:
Maak een onmiddellijke wrapper voor elke functie die dat niet doet
In ons geval is dat gemakkelijk met Q's node-interfacing helpers:
var find = Q.nbind(Prayer.find, Prayer);
Nu hebben we alleen maar beloften en hebben we geen uitstel meer nodig. Derde regel komt in het spel:
Alles wat iets doet met een async resultaat gaat in een .then
terugbellen
...en geeft het resultaat terug. Verdorie, dat resultaat kan zelfs een belofte zijn als "iets" asynchroon was! Hiermee kunnen we de volledige callback-functie schrijven:
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 hebben we iets ingewikkelders:een lus. Herhaaldelijk aanroepen van getPrayerCount()
zal ons meerdere beloften opleveren, waarvan de asynchrone taken parallel lopen en in onbekende volgorde worden opgelost. We willen op ze allemaal wachten - d.w.z. een belofte krijgen die met alle resultaten wordt opgelost wanneer elk van de taken is voltooid.
Probeer voor zulke ingewikkelde taken niet zelf een oplossing te bedenken:
Controleer de API van uw bibliotheek
En daar vinden we Q.all
, die precies dit doet. Schrijven getPrayerInCat
is nu een makkie:
function getPrayerInCat(data) {
var promises = data.map(getPrayerCount); // don't use forEach, we get something back
return Q.all(promises);
// ^^^^^^ Rule 1
}
Als we iets moesten doen met de array die Q.all
besluit, pas regel 3 toe.