8

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

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

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

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

  1. 就在我定义它之后。我需要根据它设置一个范围变量。
  2. 在另一个范围方法中,$scope.isAdmin()

对于第 2 点,可能会问为什么我不直接在 $scope.isAdmin() 方法中使用 $scope.user。问题是,有可能在用户的异步请求返回之前调用 $scope.isAdmin(),在这种情况下,我需要在从 $scope.isAdmin() 返回之前“阻止”。

我的问题是,$scope.isAdmin() 如何让 Angular 认为“监视”变量已更改并且摘要周期需要再次运行?

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

1 回答 1

14

所以我终于弄清楚了自己的问题,并认为我会为其他人回答,以防其他人发现此信息有用。

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

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

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

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

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

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

  return user;
};

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

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

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

于 2014-07-09T12:45:24.440 回答