来自firebase数据库的变量为';尽管有外部声明,但在全球范围内看不到。(javascript)

来自firebase数据库的变量为';尽管有外部声明,但在全球范围内看不到。(javascript),javascript,firebase,firebase-realtime-database,global-variables,Javascript,Firebase,Firebase Realtime Database,Global Variables,在过去的几个小时里,我一直在研究局部变量和全局变量。我从这个问题“”和其他几个问题中发现,如果变量是在函数之前声明的(在函数之外),那么当您想要更新函数中的变量时,您只需说“variable=blank”,而不说“var” 如果您查看下面的功能,我有三个警报,所有警报都通过firebase向当前登录用户的用户名发出警报。firebase引用中的第一个警报显示用户名no problem。另外两个警报“未定义”。我需要能够在所有三个位置引用变量,是否我做错了什么?或者有没有另一种方法可以做到这一点,

在过去的几个小时里,我一直在研究局部变量和全局变量。我从这个问题“”和其他几个问题中发现,如果变量是在函数之前声明的(在函数之外),那么当您想要更新函数中的变量时,您只需说“variable=blank”,而不说“var”

如果您查看下面的功能,我有三个警报,所有警报都通过firebase向当前登录用户的用户名发出警报。firebase引用中的第一个警报显示用户名no problem。另外两个警报“未定义”。我需要能够在所有三个位置引用变量,是否我做错了什么?或者有没有另一种方法可以做到这一点,而且可能更有效

var database = firebase.database();
var username;

function initApp() {
  // Listen for auth state changes.
  // [START authstatelistener]
  firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
      // User is signed in.
      var displayName = user.displayName;
      var email = user.email;
      var emailVerified = user.emailVerified;
      var photoURL = user.photoURL;
      var isAnonymous = user.isAnonymous;
      var uid = user.uid;
      var providerData = user.providerData;

      var ref = firebase.database().ref("users/" + uid);
      ref.once("value").then(function(snapshot) {
        username = snapshot.child("username").val();
        alert(username);
      });
      alert(username);
    }
  });
}
alert(username);

window.onload = function() {
  initApp();
};

我理解这可能与其他问题类似,但尽管有许多不同的方法,这些答案似乎并不奏效。提前感谢您的帮助,我希望这只是一个愚蠢的错误。

我认为您对代码的异步性质感到困惑。您的用户名仅在以下回调中可用:

ref.once("value").then(function(snapshot) {
  username = snapshot.child("username").val();
  alert(username);
});
因为
ref.once(“value”)
是异步的(紧跟在上述代码块之后的
警报将始终在
回调执行之前调用)。任何依赖于
username
的代码都必须确保异步调用在执行之前完成

有许多方法可以实现这一点,例如:
async/await
,从
initApp
函数返回
Promise
,或者更改
initApp
以接受在异步内容完成后运行依赖代码的回调。下面是一个返回
承诺的示例:

function initApp() {
  return new Promise(function(resolve, reject) {
    // Listen for auth state changes.
    // [START authstatelistener]
    firebase.auth().onAuthStateChanged(function(user) {
      if (user) {
        // User is signed in.
        var displayName = user.displayName;
        var email = user.email;
        var emailVerified = user.emailVerified;
        var photoURL = user.photoURL;
        var isAnonymous = user.isAnonymous;
        var uid = user.uid;
        var providerData = user.providerData;

        var ref = firebase.database().ref("users/" + uid);
        ref.once("value").then(function(snapshot) {
          username = snapshot.child("username").val();
          resolve(username);
        });
      } else {
        // no username, reject
        reject("User is not logged in")
      }
    });
  });
}

window.onload = function() {
  initApp().then(function(username) {
    alert(username);
    // do things that depend on user/username
  }).catch(function(error) {
    alert(error);
  });
};
一旦
承诺到位
,您就可以使用它让代码感觉更加同步:

window.onload = async function() {
  try {
    const username = await initApp();
    alert(username);
  } catch(e) {
    alert(e);
  }
};

请记住,您仍然无法在该函数之外对用户名发出警报-任何依赖异步数据的代码都必须等待该数据准备就绪,即在
中处理,然后
/callback/等。

谢谢!有没有办法使它不异步?这样我就可以创建其他函数并随时引用用户名了?对不起,我没问题,没问题!不,您不能使其同步,firebase是浏览器必须向其发出请求的远程服务-如果它是同步的,那么它将在等待请求完成时完全阻止浏览器进程(所有选项卡等)。您可以通过使用使其“感觉”同步,我将更新我的答案,说明这可能如何工作,请记住,async/await在较旧的浏览器上不起作用。它是用于chrome扩展的,所以希望一切正常,非常感谢您的帮助!我之前问过一个类似的问题,它被标记为重复,并将我发送到一个关于异步和同步的页面。我不知道他们的意思,所以我当然更困惑了。我真的很感谢你的详细解释,至少现在我明白了,所以我真的非常感谢你!很乐意帮忙!:-)我强烈推荐这段关于Javascript事件循环的视频——它是对JS中异步代码的精彩(有趣)解释。祝你好运