从 Firebase 3.x 中的控制器获取 firebase.User 的明显竞争条件

Apparent race condition getting firebase.User from controller in Firebase 3.x

我正在使用 Firebase 3.x 和身份验证状态更改事件来分配我服务中的当前用户 -

.service('FireService', 函数 ($q, $http,$state) {

var accessToken;
var user;

firebase.auth().onAuthStateChanged(function (usr) {
  if (usr) {
    // User signed in!
    user = usr;
  } else {
    user = null;
    $state.go('login');
  }
});

return {

  currentUser: function () {
    return user;
  }
}

但我需要当前用户从控制器中的数据库中引用我的子对象

var getLog = function () {
  var logRange = currentDate.format('MMMYYYY').toUpperCase();
  var userId = FireService.currentUser().uid;
  var ref = LogService.logs(userid,logRange);
  // download the data into a local object
  ref.once('value').then(
    function (result) {
      logObj = result;
    })
};

当我设置断点时,我看到 currentUser() 始终为空,因为状态更改尚未触发。我也尝试过直接从 firebase.User 分配我的用户 ID,但是当我的控制器准备好时,它还没有初始化。如何获取当前登录的用户,以便在我开始在我的应用程序中进行路由之前可用?

我建议直接在 getLog 方法中使用观察者,这样它会等到当前用户被设置:

var getLog = function () {
  var unsubscribe = firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
      var logRange = currentDate.format('MMMYYYY').toUpperCase();
      var userId = user.uid;
      var ref = LogService.logs(userid,logRange);
      // download the data into a local object
      ref.once('value').then(
        function (result) {
          logObj = result;
        });
    }
    unsubscribe(); // So this observer is only triggered once.
  });
};

由于 ref.once('value') 无论如何都是异步解析的,它只会给方法增加一点延迟,但不会改变其行为。

使用此 "one off" 观察者模式(第一次调用其 unsubscribe 函数的观察者)允许您确保 Firebase Auth在执行代码之前完全初始化。如果在您创建观察者时 Firebase Auth 已经初始化,那么它的解析将立即被触发。请记住,观察者总是被异步调用。

如果您最终经常使用这种模式,您可以在 FireService 上添加一个方法:

...
ready: function() {
  return $q(function(resolve, reject) {
    var unsubscribe = firebase.auth().onAuthStateChanged(function(user) {
      unsubscribe();
      resolve(user);
    });
  });
}
...

并在您的 getLog 方法中使用它:

var getLog = function () {
  FireService.ready().then(function(user) {
    if (!user) { return; }
    var logRange = currentDate.format('MMMYYYY').toUpperCase();
    var userId = user.uid;
    var ref = LogService.logs(userid,logRange);
    // download the data into a local object
    ref.once('value').then(
      function (result) {
        logObj = result;
      });
  });
};