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

Mat*_*son 10 javascript ajax asynchronous firebase

好几次,我遇到了使用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());
Run Code Online (Sandbox Code Playgroud)

当然,上面的代码不起作用,因为firebaseRef.once()是异步调用,所以velocity当我们到达时还没有设置return velocity;.如果我们将回调函数置于return内部.on(),则根本不会返回任何内容.

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

另一种解决方案是存储同步读取但从Firebase异步更新的Firebase缓存版本.

这些解决方案中的一个比另一个好吗?还有更好的解决方案吗?

Kat*_*ato 9

另一种方法是使用Promise策略.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); });
Run Code Online (Sandbox Code Playgroud)

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


Mic*_*uer 8

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

例如,我们注意到"动作游戏"通常由紧密的渲染循环驱动,而不是由firebase数据更改事件驱动.因此,缓存最新的Firebase数据以便在渲染循环中使用是有意义的.例如:

var latestSnapshot = null;
firebaseRef.on('value', function(snap) { latestSnapshot = snap; });
Run Code Online (Sandbox Code Playgroud)

然后你可以在渲染循环(或其他任何地方)中同步使用latestSnapshot,但是在第一次firebase回调发生之前你需要小心处理它为null.


Ron*_*lev 6

与@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); });
Run Code Online (Sandbox Code Playgroud)