在函数中处理异步调用(Firebase)

时间:2022-12-28 10:59:08

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:

现在我已经多次遇到使用Firebase的同步和异步函数的问题。我的问题是,我经常需要在我编写的函数中进行异步的Firebase调用。作为一个简单的例子,假设我需要计算和显示一个物体的速度,我的Firebase存储距离和时间:

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.

当然,上面的代码不会起作用,因为firebaseRef.once()是一个异步调用,所以当我们到达返回速度时,速度还没有设置。如果我们将return放在.on()回调函数中,则不会返回任何内容。

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

一个解决方案是使我的calcVelocity()函数也是异步的。

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

另一种解决方案是存储一个缓存版本的Firebase,该版本可以同步读取,但可以从Firebase异步更新。

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

其中一个解决方案比另一个更好吗?有更好的解决方案吗?

3 个解决方案

#1


8  

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.

您确定了两种可能性:要么使您的函数也是异步的,要么缓存最新的Firebase数据,以便您可以同步访问它。考虑到你正在编写的应用程序的上下文,你使用哪一个只是一个偏好和方便的问题。

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:

例如,我们注意到,“动作游戏”通常是由一个紧密的呈现循环驱动的,而不是由firebase数据更改事件驱动的。因此,缓存最新的基本数据以便在呈现循环中使用是有意义的。例如:

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.

然后,您可以在呈现循环(或其他任何地方)中同步使用latestSnapshot,不过在第一个firebase回调发生之前,您需要小心地将其处理为null。

#2


9  

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

另一种方法是利用承诺策略。jQuery有一个很好的例子。

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!

还要记住snapshot.val().distance;如果snapshot.val()返回null,则可能返回错误!

#3


6  

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

与@Kato提供的答案相同,但是在Firebase中内置的承诺看起来是这样的

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

#1


8  

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.

您确定了两种可能性:要么使您的函数也是异步的,要么缓存最新的Firebase数据,以便您可以同步访问它。考虑到你正在编写的应用程序的上下文,你使用哪一个只是一个偏好和方便的问题。

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:

例如,我们注意到,“动作游戏”通常是由一个紧密的呈现循环驱动的,而不是由firebase数据更改事件驱动的。因此,缓存最新的基本数据以便在呈现循环中使用是有意义的。例如:

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.

然后,您可以在呈现循环(或其他任何地方)中同步使用latestSnapshot,不过在第一个firebase回调发生之前,您需要小心地将其处理为null。

#2


9  

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

另一种方法是利用承诺策略。jQuery有一个很好的例子。

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!

还要记住snapshot.val().distance;如果snapshot.val()返回null,则可能返回错误!

#3


6  

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

与@Kato提供的答案相同,但是在Firebase中内置的承诺看起来是这样的

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