Handling Asynchronous Calls (Firebase) in functions

Several times now I have run into an issue with synchronous & asynchronous functions using Firebase. My problem is often that I need to make an asynchronous Firebase call within a function that I wrote. As a simple example, suppose I need to calculate & display the velocity of an object, and my Firebase stores distance & time:

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());

Of course, the above code will not work because firebaseRef.once() is an asynchronous call, so velocity has not been set yet when we reach return velocity;. If we place the return inside the .on() callback function, then nothing is returned at all.

One solution would be to make my calcVelocity() function asynchronous as well.

Another solution would be to store a cached version of the Firebase that is read synchronously but updated asynchronously from the Firebase.

Is one of these solutions better than the other? And is there a better solution?


Another approach is to utilize a Promise strategy. jQuery has a great one.

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); });

Keep in mind also that snapshot.val().distance; may return an error if snapshot.val() returns null!


You nailed the two possibilities: Either make your function asynchronous as well, or cache the latest Firebase data so you can access it synchronously. Which one you use is just a matter of preference and convenience, given the context of the app you're writing.

For instance, we've noticed that "action games" are usually driven by a tight render loop instead of by firebase data change events. So it makes sense to cache the latest Firebase data for use in your render loop. For example:

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

And then you can use latestSnapshot synchronously in your render loop (or wherever else), though you need to be careful to deal with it being null until the first firebase callback happens.


Same idea as in the answer @Kato provided, but with the built-in promises in Firebase would look something like this

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); });