AngularJS - 为什么$ scope。$ apply会影响其他范围

时间:2014-01-29 07:05:18

标签: angularjs

在我的AngularJS应用程序中,我有2个未嵌套的控制器。调用$ scope。$ apply方法似乎也会影响其他兄弟范围。

在下面的jsfiddle中,似乎每当ControllerTwo每秒更新一次时,就会评估ControllerOne的{{doubleMe(x)}}表达式。这可以从控制台消息中显示。

我可以理解为什么只要文本输入(在同一范围内)发生变化就会对该表达式进行求值,但是为什么$ scope。$适用于另一个范围会导致该表达式也被重新评估?

请注意,我可以通过使用$ timeout来避免$ scope。$ apply,但会观察到结果。

    <!-- HTML file -->
    <div ng-app>
        <h1>Root</h1>
        <div ng-controller="ControllerOne">
            <h2>Scope One</h2>
            1 * 2 =  {{doubleMe(1)}}<br/>
            2 * 2 =  {{doubleMe(2)}}<br/>
            3 * 2 =  {{doubleMe(3)}}<br/>
            <input ng-model="text">
        </div>

        <div ng-controller="ControllerTwo">
            <h2>Scope Two</h2>
            {{clock.now | date:'yyyy-MM-dd HH:mm:ss'}}
        </div>
    </div>

// js file

    function ControllerOne($scope) {
        var counter=1;
        $scope.doubleMe = function(input) {
            console.log(counter++);
            return input*2;
        }
        $scope.text = "Change Me";
    }

    function ControllerTwo($scope) {
        $scope.clock = {
            now: new Date()
        };

        var updateClock = function() {
            $scope.clock.now = new Date()
        };

        setInterval(function() {
            $scope.$apply(updateClock);
        }, 1000);
    }

2 个答案:

答案 0 :(得分:4)

正如您所见$scope.$apply = $rootScope.$digest //+ some error handling,因为$scope.$apply使用$ rootScope,它会影响其所有后代。

所以如果更新子作用域,可以调用$scope.$digest来仅检查该作用域及其后代,从而减少脏检查的数量并提高性能。

示例

我更改了您的代码并添加了$ digest。

setInterval(function() {
             $scope.clock.now = new Date();
            $scope.$digest();
        }, 1000);

实例: http://jsfiddle.net/choroshin/JY5sb/4/

答案 1 :(得分:0)

来自source code

中的AngularJS文档
   * # Pseudo-Code of `$apply()`
   * <pre>
       function $apply(expr) {
         try {
           return $eval(expr);
         } catch (e) {
           $exceptionHandler(e);
         } finally {
           $root.$digest();
         }
       }
   * </pre>

Alex是正确的,如果您只想让您的更改反映在当前范围及其子项中,则scope.$digest()是可以使用的。但是,AngularJS经常不鼓励这样做,因为表达式通常会产生副作用,修改全局对象,如服务,这些对象又可以修改兄弟范围。