Iniziamo con la regola generale per l'utilizzo delle promesse:
Ogni funzione che fa qualcosa di asincrono deve restituire una promessa
Quali funzioni sono queste nel tuo caso? È getPrayerInCat
, il forEach
richiamata e Prayer.find
.
Hm, Prayer.find
non restituisce una promessa ed è una funzione di libreria, quindi non possiamo modificarla. Entra in gioco la Regola 2:
Crea un wrapper immediato per ogni funzione che non lo fa
Nel nostro caso è facile con gli helper di interfaccia dei nodi di Q:
var find = Q.nbind(Prayer.find, Prayer);
Ora abbiamo solo promesse in giro e non abbiamo più bisogno di differimenti. Entra in gioco la terza regola:
Tutto ciò che fa qualcosa con un risultato asincrono va in un .then
richiamata
...e restituisce il risultato. Diavolo, quel risultato può anche essere una promessa se "qualcosa" fosse asincrono! Con questo, possiamo scrivere la funzione di callback completa:
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
});
}
Ora abbiamo qualcosa di un po' più complicato:un loop. Chiamando ripetutamente getPrayerCount()
ci darà più promesse, le cui attività asincrone vengono eseguite in parallelo e si risolvono in un ordine sconosciuto. Vogliamo aspettarli tutti, ovvero ottenere una promessa che si risolva con tutti i risultati al termine di ciascuno dei compiti.
Per compiti così complicati, non cercare di trovare la tua soluzione:
Controlla l'API della tua libreria
E lì troviamo Q.all
, che fa esattamente questo. Scrivendo getPrayerInCat
ora è un gioco da ragazzi:
function getPrayerInCat(data) {
var promises = data.map(getPrayerCount); // don't use forEach, we get something back
return Q.all(promises);
// ^^^^^^ Rule 1
}
Se avessimo bisogno di fare qualcosa con l'array che Q.all
risolve, basta applicare la Regola 3.