解决$ rootScope:infdig Infinite $ digest循环

时间:2014-07-09 09:48:59

标签: javascript angularjs q angular-promise

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

http://jsfiddle.net/eS5e5/1/

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

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

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

    我的问题是,$ scope.isAdmin()正在让角度认为观看了一个'变量已经改变,摘要周期需要再次运行?

    $ scope.isAdmin()实际上并未改变任何内容。

    以下是精简代码:

    HTML:

    <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>
    

    和JS:

    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();
      });
    

1 个答案:

答案 0 :(得分:13)

所以我终于找到了自己的问题,并认为如果其他人可能会发现此信息有用,我会为其他人解答。

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

你放在$ scope上的所有东西都被观看了#39;包括功能。每次观看的内容都会更改$ scope。$ apply()会再次运行以应用更改。如果范围函数(例如:$ scope.isAdmin())改变其返回值,则应用&#39; apply&#39;到下一个它将触发另一个“应用”,直到事情稳定并且返回值不会发生变化。

但是在我的代码中,我返回了user.then(...),它只返回一个新的promise(由于返回值不断变化,这使得应用程序循环继续进行)。

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

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

$scope.isAdmin = function() {
  if ($scope.user) {
    return $scope.user.isAdmin;
  }

  return user;
};

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

只是为了完整性,这里是更新的jsfiddle:

http://jsfiddle.net/eS5e5/2/