【问题标题】:Running $apply on $rootScope vs any other scope在 $rootScope 上运行 $apply 与任何其他范围
【发布时间】:2020-03-18 15:53:03
【问题描述】:

$apply 函数可以在任何范围内运行,包括$rootScope。

如果我在本地范围内运行它或在 $rootScope 上运行它,是否会有所不同?

我问是因为我想创建一个辅助函数,将给定函数包装在 $apply 中。为此,我总是需要传入一个作用域,这 A) 烦人,B) 不容易,因为我不一定有本地作用域。

我希望始终在 $rootScope 上调用我的辅助函数 $apply,但如果这样做有风险,则不要这样做。

【问题讨论】:

  • 起初认为这听起来很糟糕,但搜索了一下,似乎在任何范围内调用 $apply 都会导致 $rootScope.$digest 运行,所以我不相信你会遭受任何性能损失,但值得测试一些stackoverflow.com/questions/12333410/…

标签: angularjs angularjs-scope


【解决方案1】:

在任何作用域上运行$apply 总是会产生$rootscope.$digest。唯一可能产生影响的情况是您将表达式作为参数提供给$apply。表达式将在当前范围内进行评估(与 $rootScope 相比),但之后会总是调用$rootscope.$digest。

源码比较清楚:rootScope.js

底线: 如果您不带参数调用$apply,则没有区别。

【讨论】:

  • 如果不带参数的apply之前的代码抛出异常会有所不同。 Angular 的错误处理不会捕获该异常。
  • 你是说thisThrowsAnError();$scope.$apply()和thisThrowsAnError();$rootScope.$apply()之间有区别吗?
  • 我指的是 $anyScope.$apply(function () {/*throws error*/}) vs /*thorws error*/;$anyScope.$apply()。后一个是不经过角度的错误处理程序
  • 最佳实践:使用$timeout 而不是$rootScope.$apply() 以避免难以调试的错误“digest already in progress”
【解决方案2】:

另一个在 $rootScope 上运行 $apply 而不是 $scope 的原因通常是当我需要在服务中调用 $apply 时,该服务将由不同的控制器使用,因此适用于不同的范围。
在这种情况下,我更喜欢将$rootScope 注入服务并对其调用 $apply ,而不用担心该服务将来会在哪些范围内使用。

【讨论】:

  • 好点..实际上将范围传递给服务应该是一个记录在案的反模式
【解决方案3】:

在任何给定范围上运行 $digest/$apply 将使用深度优先遍历访问所有其他范围:

https://github.com/angular/angular.js/blob/3967f5f7d6c8aa7b41a5352b12f457e2fbaa251a/src/ng/rootScope.js#L550-L558

这意味着唯一的区别是 $digest 将从调用它的任何 $scope 开始

【讨论】:

  • $digest 将始终在 $rootScope 上调用。我在回答中解释了它。
【解决方案4】:

/* What happens with $apply */ 
angular.module('myApp',[]).controller('MessageController', function($scope) {
    
      $scope.getMessage = function() {
        setTimeout(function() {
          $scope.$apply(function() {
            //wrapped this within $apply
            $scope.message = 'Fetched after 3 seconds'; 
            console.log('message:' + $scope.message);
          });
        }, 2000);
      }
      
      $scope.getMessage();
    
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<body ng-app="myApp">
      <div ng-controller="MessageController">
        Delayed Message: {{message}}
      </div>  
    </body>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多