Javascript 解决$rootScope:infdig无限$digest循环

Javascript 解决$rootScope:infdig无限$digest循环,javascript,angularjs,q,angular-promise,Javascript,Angularjs,Q,Angular Promise,我了解了无限摘要循环的基本概念以及它是如何发生的,但我遇到了这个问题。下面是一把小提琴,演示我的代码和问题: 在JSFIDLE控制台中,您将看到无限摘要循环 基本上,我必须对可能尚未加载的数据做出决定,因此我需要等待承诺使用then()解决。我有一个承诺叫做用户。在代码中有两个不同的地方,我在用户上调用then() 就在我定义它之后。我需要基于它设置一个范围变量 在另一个scope方法中,$scope.isAdmin() 对于第2个问题,可能会问我为什么不直接在$scope.isAdmin()

我了解了无限摘要循环的基本概念以及它是如何发生的,但我遇到了这个问题。下面是一把小提琴,演示我的代码和问题:

在JSFIDLE控制台中,您将看到无限摘要循环

基本上,我必须对可能尚未加载的数据做出决定,因此我需要等待承诺使用then()解决。我有一个承诺叫做用户。在代码中有两个不同的地方,我在用户上调用then()

  • 就在我定义它之后。我需要基于它设置一个范围变量
  • 在另一个scope方法中,$scope.isAdmin()
  • 对于第2个问题,可能会问我为什么不直接在$scope.isAdmin()方法中使用$scope.user。问题是,有可能在用户的异步请求返回之前调用$scope.isAdmin(),在这种情况下,我需要在从$scope.isAdmin()返回之前“阻止”

    我的问题是,$scope.isAdmin()如何让我们认为一个“关注的”变量已经改变,摘要周期需要再次运行

    $scope.isAdmin()实际上并没有改变任何东西

    以下是简化的代码:

    HTML:


    因此,我最终解决了自己的问题,并认为我会为其他人解答,以防其他人发现这些信息有用

    修复的关键在于两个概念:角度承诺和角度手表。通过了解这两个概念并将其应用到一起,修复实际上非常简单

    您在$scope上放置的所有内容都被“监视”,包括函数。每次监视的内容更改$scope时,$apply()将再次运行以应用更改。如果一个作用域函数(例如:$scope.isAdmin())将其返回值从一个“apply”更改为下一个“apply”,它将触发另一个“apply”,直到情况稳定且返回值不变

    但是在我的代码中,我返回了user.then(…),它只返回了一个新的承诺(由于返回值不断变化,应用循环一直持续下去)

    在isAdmin()函数中,我需要延迟其返回值,直到用户实际加载(任何其他返回值都将毫无意义)。因此,我更改了代码,通过检查$scope.user检查用户异步调用是否已解决,如果已解决,则返回有效的isAdmin值。如果$scope.user仍然没有定义,我将返回我已经创建的承诺

    我将$scope.isAdmin()更改为:

    这与原始代码具有相同的效果,不会触发无限应用循环。具体地说,如果$scope.user没有解析,我们仍然会像以前一样返回一个承诺,返回用户变量。但是请注意,用户变量是相同的承诺,而不是由then()创建的新承诺,因此应用循环稳定

    为了完整起见,这里是更新的JSFIDLE:


    感谢您回答您自己的问题-这对我来说非常重要,这让我明白了我的问题:
    但在我的代码中,我是[…],它只是返回了一个新的承诺(由于返回值不断变化,应用周期一直持续下去)
    <body ng-controller='myController'>  
      <div ng-if='isAdmin()'>Hi! <strong>{{ user.username }}</strong> is an Admin!!!</div>
      <div ng-if='!isAdmin()'>Hi! <strong>{{ user.username }}</strong> is NOT an Admin!!!</div>
    </body>
    
    angular.module('myApp', [])
      .factory('myService', function($q, $timeout) {
        return {        
          getUser: function() {
            var deferred = $q.defer();
    
            $timeout(function() {
              deferred.resolve({ username: 'me', isAdmin: true });
            }, 2000);
    
            return deferred.promise;
          }
        };
      })
      .controller('myController', function($scope, $q, myService) {      
        var getUserDeferred = $q.defer();
        var user = getUserDeferred.promise;
        user.then(function(user) {
          $scope.user = user;
          return user;
        });
    
        $scope.getUser = function() {
          return myService.getUser().then(function(user) {
            getUserDeferred.resolve(user);
          });
        };
    
        $scope.isAdmin = function() {
          return user.then(function(user) {
            return user.isAdmin;
          });
        };
    
        $scope.getUser();
      });
    
    $scope.isAdmin = function() {
      if ($scope.user) {
        return $scope.user.isAdmin;
      }
    
      return user;
    };