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

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

问题描述

我正在使用Firebase和angularJS来获取用户列表。我可以使用 once()函数从我的数据库中读取所有用户,但我无法弄清楚为什么 userList 返回undefined下面

  .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){
users [key] .id = key;
/ /做一些其他的东西
}
console.log(用户); //输出所有用户
})。然后(function(){
userList = users;
console.log(userList); //输出所有用户
},(函数(错误){
alert('错误:'+错误);
});
console.log(userList); //输出'undefined'
}
}]);

我等待分配我的 userList 变量,直到我完成处理用户,但没有运气。



这里有一些重要的东西我错过Promise / callbacks的地方我在文档中找不到它;有人可以帮我理解我的问题吗?

解决方案

问题是(正如我所说的那样)数据是从Firebase异步读取的。因此代码不会按您认为的顺序执行。最简单的方法是通过几个日志语句简化它:

  .service('userService',[function() {
this.getUsers = function(){
var ref = firebase.database()。ref('/ users /');
console.log(在附加侦听器之前);
ref.once('value')。then(function(snapshot){
console.log(got value);
});
console.log(附加监听器之后);
}
}]);

这个输出将是:


附加监听器之后



得到值


知道执行的顺序应该完全解释为什么在刚刚连接监听器后无法打印用户列表。如果没有,我建议您也阅读这个好答案:如何从异步调用中返回响应吗?



现在解决方案: 在回调中返回一个承诺。



在回调中使用用户列表



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

  ref .once('value',function(snapshot){
users = snapshot.val();
for(用户的var key){
users [key] .id = key;
}
console.log(用户); //输出所有用户
})

您正在重新编写代码,首先加载用户列表,然后将其内容打印为每当加载用户列表时,打印其内容。定义上的差异很小,但突然你完全有能力处理异步加载。



你也可以做同样的承诺,就像你在你的代码:

  ref.once('value')。then(function(snapshot){
users = snapshot。 val();
for(用户的var键){
users [key] .id = key;
//做一些其他的东西
}
console。 log(users); //输出所有用户
});

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



返回承诺



经常你赢了我想把所有需要用户的代码放入 getUsers()函数中。在这种情况下,你可以 将回调传递给 getUsers()(我不会在这里显示,但它与你的回调非常相似可以传入一次()你可以从 getUsers()返回一个承诺

  this.getUsers = function(){
var ref = firebase.database()。ref('/用户/');
返回ref.once('value')。then(function(snapshot){
users = snapshot.val();
for(var key in users){
users [key] .id = key;
//做其他一些事情
}
return(用户);
})。catch(函数(错误){
alert('错误:'+错误);
});
}

使用此服务,我们现在可以调用 getUsers( )并使用生成的承诺在用户加载后获取用户:

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

并且你已经驯服了异步野兽。嗯......现在至少。即使是经验丰富的JavaScript开发人员也会偶尔混淆,所以如果需要一段时间习惯,请不要担心。


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

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

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?

解决方案

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

The output of this will be:

before attaching listener

after attaching listener

got value

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.

Use the user list in the callback

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.

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.

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

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

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天全站免登陆