【问题标题】:Using data returned from Firebase fetch Javascript使用从 Firebase 返回的数据获取 Javascript
【发布时间】:2018-04-16 09:22:06
【问题描述】:

这里是网络开发新手。我使用 Firebase 作为我的后端,并且我需要在数据库中查询一个值并使用该返回值在另一个查询中匹配到同一个数据库。

这是我的代码:

function dataLoad() {

    var valueThatINeedToUseElsewhere

    userReference.on('value',function(users){
        var currentUser = firebase.auth().currentUser.uid
        users.forEach(function(user){
            if(user.key === currentUser) {
                valueThatINeedToUseElsewhere = user.val().userName
                console.log(valueThatINeedToUseElsewhere)
            }
        })
    })
    console.log(valueThatINeedToUseElsewhere)
}

IF 条件中的console.log 记录了正确的值。然而,上面的最后一个 console.log 没有记录任何东西,尽管变量名是在“on”函数之外声明的。为什么会这样?我如何才能真正使用“on”函数之外的数据?我需要使用它在另一个数据检索操作中执行类似的 IF 条件。

谢谢!

【问题讨论】:

    标签: javascript firebase firebase-realtime-database scope


    【解决方案1】:

    你现在可能正在尝试做这样的事情:

    var valueThatINeedToUseElsewhere;
    dataLoad();
    doSomethingWith(valueThatINeedToUseElsewhere);
    

    不幸的是,这不起作用,因为(正如 Doug 所说)数据是从 Firebase 异步加载的。当您尝试使用 valueThatINeedToUseElsewhere 时,该值尚未加载。

    为什么这不起作用,一三二测试

    如果您像这样放置一些日志语句,最容易看到这一点:

    console.log("Before starting to load value")
    userReference.on('value',function(users){
        console.log("Loaded value")
    })
    console.log("After starting to load value")
    

    当你运行这段代码时,它会打印:

    开始加载值之前

    开始加载值后

    加载值

    这可能不是您期望的顺序。但它完美地解释了为什么你在尝试时不能使用 valueThatINeedToUseElsewhere:它还没有被加载。

    重新定义问题

    我发现处理这种情况的最佳方法是重新定义问题。您当前的代码是用“首先我们加载值,然后我们对值做一些事情”的逻辑编写的。对于异步加载,最好将其框定为“首先开始加载数据。一旦数据开始加载,就对其进行处理”。

    在如下代码中:

    function dataLoad() {
        userReference.once('value',function(users){
            var currentUser = firebase.auth().currentUser.uid
            users.forEach(function(user){
                if(user.key === currentUser) {
                    var valueThatINeedToUseElsewhere = user.val().userName
                    doSomethingWith(valueThatINeedToUseElsewhere)
                }
            })
        })
    }
    

    如您所见,我们已将需要数据的代码移到数据可用时触发的回调中。这样您就可以保证在您致电doSomethingWith 时数据可用。我还更改了代码以使用 once,这(正如 Doug 所说)更适合您的用例。

    还有两个步骤可以提高代码的灵活性和性能。

    传入一个被调用的函数一旦数据被加载

    首先:在最后一次更新中,对doSomethingWith 的调用是硬编码的,这意味着dataLoad()doSomethingWith 紧密联系在一起。将它们分开通常会更好。为此,我们可以将所谓的回调函数传入dataLoad,然后在加载数据时调用该函数。这非常类似于once() 所做的。让我们在实践中看看:

    function dataLoad(callback) {
        userReference.once('value',function(users){
            var currentUser = firebase.auth().currentUser.uid
            users.forEach(function(user){
                if(user.key === currentUser) {
                    var valueThatINeedToUseElsewhere = user.val().userName
                    callback(valueThatINeedToUseElsewhere)
                }
            })
        })
    }
    

    差别不大。但现在你可以像这样调用dataLoad

    dataLoad(doSomethingWith);
    

    一旦加载数据,doSomethingWith 将被调用。

    按key加载数据

    最后的改变是优化。您当前的代码正在加载所有用户,而您只需要一个并且知道他们的密钥。仅加载特定用户会更有效,其中:

    function dataLoad(callback) {
        var currentUser = firebase.auth().currentUser.uid
        userReference.child(currentUser).once('value',function(users){
            var valueThatINeedToUseElsewhere = user.val().userName
            callback(valueThatINeedToUseElsewhere)
        })
    }
    

    【讨论】:

    • 哇!感谢弗兰克提供的非常详细的回答!通过 Doug 的 Medium 帖子,我认为我的是 1,3,2 问题。您的方法正确地解决了它 - 加上您正在检索一个用户这一事实是完美的。但是,回调实际上是我需要执行的对数据库的另一个查询。再次,它将像上面一样检索单个值。我不确定如何为 Firebase 的另一个数据检索编写回调。您能对此有所了解吗?
    • 我想我明白了。一旦我得到它的工作,我会在这里回复我的解决方案。再次感谢您的精彩回复!
    【解决方案2】:

    on() 是异步的并立即返回,这意味着您的控制台日志将显示一个未定义的值。您传递给 on() 的回调只会在结果可用时运行,并且无法保证会以多快的速度发生。您应该只在异步调用完成后使用它的值 - 在某个异步调用完成之前不要尝试让您的代码阻塞。

    如果您只需要一个位置的值一次,也可以考虑使用 once() 而不是 on()。您可以在加载所需数据后使用其返回的承诺链接一些额外的工作。它也是异步的(与所有其他返回承诺的方法一样)。

    要详细了解 Firebase API 为何是异步的,以及这对您的应用意味着什么,请read this blog

    【讨论】:

    • 感谢 Doug 的快速响应 - 我确实尝试过使用 once() 但它真的很混乱。你能用 once() 而不是 on() 大致重写上面的函数吗?
    猜你喜欢
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 2021-11-21
    相关资源
    最近更新 更多