为什么 Firebase 会在 once() 函数之外丢失引用? [英] Why Does Firebase Lose Reference outside the once() Function?

查看:20
本文介绍了为什么 Firebase 会在 once() 函数之外丢失引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 Firebase 和 angularJS 来获取用户列表.我可以使用 once() 函数从我的数据库中读取所有用户,但我不明白为什么 userList 在下面返回 undefined

I'm using Firebase along with angularJS to fetch a list of users. I can read all the users from my database with the once() function, but I can't figure out why userList returns undefined below

.service('userService', [function() {
    this.getUsers = function() {
        var users;
        var userList;
        var ref = firebase.database().ref('/users/');
        ref.once('value').then(function(snapshot) {
            users = snapshot.val();
            for(var key in users) {
                users[key].id = key;
                // do some other stuff
            }
            console.log(users); // outputs all users
        }).then(function(){
            userList = users; 
            console.log(userList); // outputs all users
        },(function(error){
            alert('error:  ' + error);
        });
        console.log(userList); // outputs 'undefined'
    }
}]);

我等待分配我的 userList 变量,直到我处理完 users,但没有运气.

I wait to assign my userList variable until I'm done processing users, but no luck.

这里有一些重要的东西,我在 Promises/callbacks 方面遗漏了,我在文档中找不到它;有人可以帮助我了解我的问题吗?

There is something important here that I am missing where Promises/callbacks are concerned and I cannot find it in the documentation; could someone help me understand my issue?

推荐答案

问题是(正如 imjared 所说)从 Firebase 异步读取数据.所以代码不会按照你想的顺序执行.只需用几条日志语句将其简化,就很容易看出这一点:

The problem is (as imjared says) that the data is read from Firebase asynchronously. So the code doesn't execute in the order that you think. It's easiest to see that by simplifying it with just a few log statements:

.service('userService', [function() {
    this.getUsers = function() {
        var ref = firebase.database().ref('/users/');
        console.log("before attaching listener");
        ref.once('value').then(function(snapshot) {
            console.log("got value");
        });
        console.log("after attaching listener");
    }
}]);

输出结果为:

在附加监听器之前

附加监听器后

有价值

了解它的执行顺序应该可以完美地解释为什么在您刚刚附加侦听器后无法打印用户列表.如果没有,我建议您也阅读这个很棒的答案:How我如何从异步调用返回响应?

Knowing the order in which this executes should explain perfectly why you cannot print the user list after you've just attached the listener. If not, I recommend also reading this great answer: How do I return the response from an asynchronous call?

现在解决方案:您将要么需要在回调中使用用户列表返回一个承诺.

Now for the solution: you will either need to use the user list in the callback or return a promise.

这是处理异步代码最古老的方法:将所有需要用户列表的代码移到回调中.

This is the oldest way to deal with asynchronous code: move all code that needs the user list into the callback.

    ref.once('value', function(snapshot) {
        users = snapshot.val();
        for(var key in users) {
            users[key].id = key;
        }
        console.log(users); // outputs all users
    })

您正在从首先加载用户列表,然后打印其内容"重构您的代码;到每当加载用户列表时,打印其内容".定义上的差异很小,但突然间您就完全具备了处理异步加载的能力.

You're reframing your code from "first load the user list, then print its contents" to "whenever the user list is loaded, print its contents". The difference in definition is minor, but suddenly you're perfectly equipped to deal with asynchronous loading.

你也可以对 promise 做同样的事情,就像你在代码中所做的一样:

You can also do the same with a promise, like you do in your code:

   ref.once('value').then(function(snapshot) {
        users = snapshot.val();
        for(var key in users) {
            users[key].id = key;
            // do some other stuff
        }
        console.log(users); // outputs all users
    });

但是使用承诺比直接使用回调有一个巨大的优势:你可以返回承诺.

But using a promise has one huge advantage over using the callback directly: you can return a promise.

通常您不想将需要用户的所有代码都放入getUsers() 函数中.在这种情况下,您可以要么将回调传递给 getUsers()(我不会在这里展示,但它与您可以传递给 的回调非常相似)once()) 或者你可以从getUsers()返回一个promise:

Often you won't want to put all the code that needs users into the getUsers() function. In that case you can either pass a callback into getUsers() (which I won't show here, but it's very similar to the callback you can pass into once()) or you can return a promise from getUsers():

this.getUsers = function() {
    var ref = firebase.database().ref('/users/');
    return ref.once('value').then(function(snapshot) {
        users = snapshot.val();
        for(var key in users) {
            users[key].id = key;
            // do some other stuff
        }
        return(users);
    }).catch(function(error){
        alert('error:  ' + error);
    });
}

有了这个服务,我们现在可以调用 getUsers() 并使用结果承诺在用户加载后获取它们:

With this service, we can now call getUsers() and use the resulting promise to get at the users once they're loaded:

userService.getUsers().then(function(userList) {
    console.log(userList);
})

这样你就驯服了异步野兽.嗯……至少现在是这样.即使是经验丰富的 JavaScript 开发人员,这也会偶尔让他们感到困惑,所以如果需要一些时间来适应,请不要担心.

And with that you have tamed the asynchronous beast. Well.... for now at least. This will keep confusing even seasoned JavaScript developers once in a while, so don't worry if it takes some time to get used to.

这篇关于为什么 Firebase 会在 once() 函数之外丢失引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆