2016-11-19 21 views
2

我正在使用Firebase以及angularJS来获取用户列表。我可以从我与once()函数读取数据库的所有用户,但我想不出为什么userList返回undefined下面为什么Firebase在once()函数之外失去引用?

.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,但没有运气。

这里有一些重要的信息,我错过了承诺/回调的位置,我在文档中找不到它;有人能帮我理解我的问题吗?

回答

1

你需要考虑异步:

.service('userService', [function() { 
    this.getUsers = function() { 
     var users; 
     var ref = firebase.database().ref('/users/'); 

     <!-- this happens ASYNC --> 
     ref.once('value', function(snapshot) { 
      users = snapshot.val(); 
      for(var key in users) { 
       users[key].id = key; 
       // do some other stuff 
      } 
      console.log(users); // outputs all users 
     },function(error){ 
      alert('error: ' + error); 
     }); 
     <!-- end async action --> 

     console.log(users); // outputs 'undefined' 
    } 
}]); 

我敢打赌,如果你这样做,你会被罚款:

.service('userService', [function() { 
    this.getUsers = function() { 
     var users; 
     var ref = firebase.database().ref('/users/'); 

     <!-- this happens ASYNC --> 
     ref.once('value', function(snapshot) { 
      users = snapshot.val(); 
      for(var key in users) { 
       users[key].id = key; 
       // do some other stuff 
      } 
      console.log(users); // outputs all users 
     },function(error){ 
      alert('error: ' + error); 
     }); 
     <!-- end async action --> 

     window.setTimeout(function() { 
      console.log(users); // outputs 'undefined' 
     }, 1500); 
    } 
}]); 

每直率的评论澄清:

我应进一步明确那setTimeout只会证明这是一个时间问题。如果你在你的应用中使用setTimeout,你可能会有一段糟糕的时间,因为你无法可靠地等待n毫秒的结果,你需要得到它们,然后发出回调或解决承诺后,获得快照数据。

+0

谢谢@imjared,我包含一些额外的逻辑,以确保我的异步函数在我的代码中成功完成后填充'userList' –

+2

'setTimeout()'可能会或可能不会工作(主要取决于您的网络延迟) ,但它从来没有**这个问题的正确解决方案。正确的解决方案是将需要“用户”列表的代码移动到回调/然后块中。 –

4

问题是(如上所述),数据是从Firebase异步读取的。所以代码不会按照您的想法执行。这是最容易看到,只有几个日志语句简化IT:

.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 do I return the response from an asynchronous call?

现在的解决方案:你会要么需要用到的用户列表回调返回一个承诺。

使用用户列表回调

这是为了处理异步代码的最古老的方式:移动需要用户列表步入回调的所有代码。

ref.once('value', function(snapshot) { 
     users = snapshot.val(); 
     for(var key in users) { 
      users[key].id = key; 
     } 
     console.log(users); // outputs all 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 
    }); 

但是使用诺拥有直接使用回调一个巨大的优势:可以回报承诺

返回一个承诺

通常你不会希望把所有需要用户到getUsers()函数的代码。在这种情况下,你可以要么传递回调到getUsers()(我不会在这里显示,但它是非常相似的回调可以传递到once()可以返回从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(),然后用这个承诺在用户一旦他们加载获得:

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

而且与你驯服的野兽异步。那么......至少现在。即使经验丰富的JavaScript开发人员偶尔会遇到困惑,所以如果需要一些时间来适应,也不用担心。

相关问题