Gestione delle chiamate asincrone (Firebase) nelle funzioni

Diverse volte ho avuto un problema con le funzioni sincrone e asincrone con Firebase. Il mio problema è spesso che ho bisogno di creare una chiamata Firebase asincrona all’interno di una funzione che ho scritto. Come semplice esempio, supponiamo di dover calcolare e visualizzare la velocità di un object, e il mio Firebase memorizza la distanza e il tempo:

function calcVelocity() { var distance, time, velocity; firebaseRef.once('value', function(snapshot) { distance = snapshot.val().distance; time = snapshot.val().time; velocity = distance / time; }); return velocity; } $("#velocity").html(calcVelocity()); 

Ovviamente, il codice sopra non funzionerà perché firebaseRef.once() è una chiamata asincrona, quindi la velocity non è stata ancora impostata quando raggiungiamo la return velocity; . Se inseriamo il return all’interno della funzione di .on() , non viene restituito nulla.

Una soluzione sarebbe quella di rendere la mia funzione calcVelocity() asincrona.

Un’altra soluzione potrebbe essere quella di memorizzare una versione cache di Firebase che viene letta in modo sincrono ma aggiornata in modo asincrono dal Firebase.

Una di queste soluzioni è migliore dell’altra? E c’è una soluzione migliore?

Hai individuato le due possibilità: o rendi la tua funzione asincrona, oppure memorizza nella cache gli ultimi dati Firebase in modo da poterli accedere in modo sincrono. Quello che usi è solo una questione di preferenza e convenienza, dato il contesto dell’app che stai scrivendo.

Ad esempio, abbiamo notato che i “giochi di azione” sono generalmente guidati da un ciclo di rendering limitato anziché da eventi di modifica dei dati di Firebase. Quindi ha senso memorizzare nella cache gli ultimi dati di Firebase da utilizzare nel ciclo di rendering. Per esempio:

 var latestSnapshot = null; firebaseRef.on('value', function(snap) { latestSnapshot = snap; }); 

E quindi puoi usare latestSnapshot in modo sincrono nel tuo ciclo di rendering (o in qualsiasi altro posto), anche se devi stare attento a considerare che è nullo fino a quando non avviene la prima callback di Firebase.

Un altro approccio consiste nell’utilizzare una strategia Promessa. jQuery ha un grande .

 function calcVelocity() { var distance, time, velocity, def = $.Deferred(); firebaseRef.once('value', function(snapshot) { distance = snapshot.val().distance; time = snapshot.val().time; def.resolve( distance / time ); }); return def.promise(); } calcVelocity().then(function(vel) { $("#velocity").html(vel); }); 

Tieni presente anche quella distanza di snapshot.val().distance; potrebbe restituire un errore se snapshot.val() restituisce null!

La stessa idea della risposta fornita da @Kato, ma con le promesse predefinite in Firebase sarebbe simile a questa

 function calcVelocity(snapshot) { var distance, time, velocity; distance = snapshot.val().distance; time = snapshot.val().time; return distance / time; } function getVelocity() { return firebaseRef.once('value').then(calcVelocity); } getVelocity().then(function(vel) { $("#velocity").html(vel); });