【问题标题】:Angular promise .then() repeated?Angular 承诺 .then() 重复了吗?
【发布时间】:2016-11-22 00:24:56
【问题描述】:

我有一个函数,它返回一个承诺,如果用户当前登录,该承诺将被解决,或者在用户登录后等待解决。所以你可以这样做......

myService.waitForLogin().then(function(){
    // Subscribe to pusher.com events
});

然后,当用户注销时,我使用类似的调用取消订阅事件。

问题是我想在每次用户登录时运行我的 .then() 代码,所以过程是....

  • 如果用户已登录,则运行代码。

  • 如果没有,请等他们登录后再运行代码。

  • 如果他们注销然后重新登录,请再次运行代码。

我最初使用 $rootscope.$on 来监听登录/退出事件,这对于重复发生的事件非常有效,但我需要它是基于用户已经登录的情况下的承诺。

这是我的代码:

var defer = $q.defer();

if(isLoggedIn()){
    defer.resolve();
}

else{

    var offLoggedInTrue = $rootScope.$on('loggedin-true', function(){
        defer.resolve();
        offLoggedInTrue();
    });

}

return defer.promise;

【问题讨论】:

  • Promise 只能得到一次解决......根据定义。也许您应该尝试使用其他异步系统,例如 Rx.Observable(尽管这是一个完全不同的 API)
  • 如果用户已经登录,你也可以手动触发'loggedin-true'事件。
  • 我不确定 rxjs 是否可行。基本上,是的,这是可能的,但我们都知道,window.setTimeout 有一个最大限制。还要记住移动浏览器问题,由于安全和 GUI 冻结原因,没有实现 window.setTimeout。但是你可以适当地在一个间隔内发出事件,检查用户是否登录。或者更好:改变你的概念。还有许多其他方法可以完成这项常见任务。也许您可以使用 REST 请求到您的后端定期检索用户状态。

标签: javascript angularjs promise angular-promise


【解决方案1】:

您可以使用promise通过在您的服务上存储一个deferred来控制登录状态,然后通过您的方法waitForLogin()返回promise。但是,您可以通知它,而不是解决承诺,一旦您解决了登录承诺,它将不会再次被解决,因此您可以notify 并尽可能多次重复使用它。

注意:这是一个使用 Promise 的解决方案,但是您可能会发现更好的使用事件,在我看来它更容易维护。

例如:

angular.module('myApp', [])
  .service('LoginStatusService', function($q) {

    // store a deferred to represent the login resolution state
    var loginDeferred = $q.defer();

    // the getter method to yout login promise
    this.waitForLogin = function() {
      return loginDeferred.promise;
    };

    // an example login method from where you could notify the login promise
    this.login = function(login, password) {
      /// do async login things and then
      loginDeferred.notify();
    };

    // when the deferred may need to got reseted
    this.logoff = function(login, password) {
      /// do logoff things and then
      // loginPromise = $q.defer();
    };
  })

然后在您的控制器或您想要的任何提供程序上,您可以注入服务并像这样使用它:

  .controller('MyController', function(LoginStatusService) {

    LoginStatusService.waitForLogin().then(null, null, function () {
      // do your subscribe stuff here
    });
  });

【讨论】:

  • 谢谢,但如果我没记错的话,这仍然只会触发一次,不是吗?
  • @jonhobbs 是的,你是对的,我已经更新了我的答案,而不是使用 resolve,你可以使用 notify。这可能会帮助你解决这个问题。
  • 谢谢,我认为这是我应该接受的答案,但我对无限期地使用通知并且从不解决或拒绝承诺感到有点不舒服。你能看到这样做的任何副作用吗?是否应该在某个时候强制解决/拒绝?
  • 不,我不知道。但我认为最好的方法是使用观察者模式,但它与promises不同。
  • @jonhobbs 看看这个告诉我它是否适合你的目的github.com/lenilsondc/ng-observer
【解决方案2】:

您可以继续使用“loggedin-true”,订阅事件后,如果用户已经登录,您可以手动触发事件。这里是一个小示例。

angular.module('app', [])
  .controller("mainController", function($scope, $rootScope) {
    $scope.output = "";
    $rootScope.$on('loggedin-true', function() {
      $scope.output += "loggedin event \n";
    });
    if (isLoggedIn()) {
      $rootScope.$emit("loggedin-true");
    }
    logOut($scope);
    logIn($scope, $rootScope);
  });

function isLoggedIn() {
  return true;
}

function logOut($scope) {
  $scope.output += "loggedout \n";
}

function logIn($scope, $rootScope) {
  $scope.output += "login \n";
  //login successfull
  $rootScope.$emit("loggedin-true");
}
<div ng-app="app" ng-controller="mainController">
  <pre>{{output}}<pre>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

【讨论】:

  • 谢谢 Sniels,我想我已经知道我可以做到这一点,但我希望这个功能易于使用,并且我想让它保持干燥,因为其他开发人员将调用我的waitForLogin() 函数,我不希望他们每次都编写大量逻辑。不过感谢您的回答。
  • 如果你想让它更干燥,我建议把它放在一个服务中并将它注入你的控制器。我不喜欢在服务中使用范围,但我不会为 EventEmitter 逻辑提取库,因为它已经在 Angular 中了。这是a blogpost 如何将其包装到服务中。
猜你喜欢
  • 2016-01-21
  • 2020-04-27
  • 2017-08-19
  • 2019-04-21
  • 1970-01-01
  • 2021-10-17
  • 1970-01-01
  • 2016-11-25
  • 2015-01-23
相关资源
最近更新 更多