问题是(正如 imjared 所说)数据是从 Firebase 异步读取的。所以代码不会按照你想象的顺序执行。通过仅使用一些日志语句来简化它,最容易看出这一点:
.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");
}
}]);
其输出将是:
在附加监听器之前
附加监听器后
得到了价值
了解其执行顺序应该可以完美解释为什么在附加侦听器后无法打印用户列表。如果没有,我建议您也阅读这个很棒的答案:如何从异步调用返回响应 https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call
现在给出解决方案:您将either需要在回调中使用用户列表or返回一个承诺。
在回调中使用用户列表
这是处理异步代码的最古老的方法:将所有需要用户列表的代码移至回调中。
ref.once('value', function(snapshot) {
users = snapshot.val();
for(var key in users) {
users[key].id = key;
}
console.log(users); // outputs all users
})
您正在将代码从“首先加载用户列表,然后打印其内容”重新构造为“每当加载用户列表时,打印其内容”。定义上的差异很小,但突然间您就完全有能力处理异步加载了。
您也可以对 Promise 执行相同的操作,就像在代码中所做的那样:
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
});
但使用 Promise 比直接使用回调有一个巨大的优势:you can return一个承诺.
返回一个承诺
通常您不想将需要用户的所有代码放入getUsers()
功能。在这种情况下你可以either将回调传递给getUsers()
(我不会在这里展示,但它与您可以传递给的回调非常相似once()
) or你可以返回一个承诺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 开发人员偶尔也会感到困惑,所以如果需要一些时间来适应,请不要担心。
使用异步和等待
现在该函数返回一个承诺,您可以使用async
/await
让上面的最终调用看起来更熟悉一些:
function getAndLogUsers() async {
const userList = await userService.getUsers();
console.log(userList);
}
您可以看到这段代码看起来几乎像同步调用,这要归功于使用await
关键词。但为了能够使用它,我们必须标记getAndLogUsers
(或者我们使用的任何父范围await
) as async
, 意思就是it返回一个Future
也。所以有人打电话getAndLogUsers
仍然需要了解其异步性质。