Javascript 为什么angularjs在每次输入更改时都不必要地调用控制器函数,以及如何停止这种行为?

Javascript 为什么angularjs在每次输入更改时都不必要地调用控制器函数,以及如何停止这种行为?,javascript,angularjs,Javascript,Angularjs,下面是一个使用angularjs构建的非常简单的TODO应用程序 到目前为止,它工作正常,但我的问题是angularjs在输入字段中的evry击键时一直调用“剩余”函数!!下面的代码有什么问题吗 <!doctype html> <html ng-app> <head> <link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesh

下面是一个使用angularjs构建的非常简单的TODO应用程序

到目前为止,它工作正常,但我的问题是angularjs在输入字段中的evry击键时一直调用“剩余”函数!!下面的代码有什么问题吗

<!doctype html>
<html ng-app>

<head>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
    <link href="style.css" rel="stylesheet">
</head>

<body>
    <div>
        <h2>TODO:</h2>
        <div ng-controller="TodoCtrl">
            <span>{{remaining()}} of {{todos.length}} remaining</span> [ <a href="" ng-click="archive()">archive</a> ]
            <ul class="list-unstyled">
                <li ng-repeat="todo in todos">
                    <input type="checkbox" ng-model="todo.done" >
                    <span>{{todo.text}}</span>
                </li>
            </ul>
            <form ng-submit="addTodo()">
                <input type="text" ng-model="todo" placeholder="Enter your task here">
            <form>
        </div>
    </div>

    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js"></script>
    <!--script src="app.js"></script-->
    <script>
    function TodoCtrl($scope) {
        $scope.todos = [
            {text: 'learn angular', done:true},
            {text: 'build an angular app', done:false}
        ];

        $scope.remaining = function() {
            console.log('calling remaining()');
            var count = 0;
            angular.forEach($scope.todos, function(todo) {
                count += todo.done? 0:1;
            });

            return count;
        };

        $scope.addTodo =  function() {
            if($scope.todo)  {
                $scope.todos.push({text: $scope.todo, done:false});
            }
            $scope.todo = '';
        };
    }
    </script>
</body>
</html>

待办事项:
{{todos.length}}剩余[]中的{restining()}}
  • {{todo.text}
函数TodoCtrl($scope){ $scope.todos=[ {text:'learn angular',done:true}, {text:'构建角度应用程序',完成:false} ]; $scope.remaining=函数(){ log('calling remaining()'); var计数=0; angular.forEach($scope.todos,function(todo){ 计数+=todo.done?0:1; }); 返回计数; }; $scope.addTodo=函数(){ if($scope.todo){ $scope.todos.push({text:$scope.todo,done:false}); } $scope.todo=''; }; }
这是标准的角度行为。在对模型或任何其他绑定或角度事件进行任何更改时,它将执行在示波器上设置的所有手表。这称为摘要周期,通常由$scope.$apply()触发。这就是为什么在视图中不要对从绑定表达式调用的函数进行任何繁重计算的原因


性能问题通常发生在函数在长列表上执行某些计算或筛选时。如果这是一个问题,解决方案是在集合上设置一个监视,并仅在集合更改时将计算属性作为作用域中的separat变量进行更新。在您的示例中,这将防止在不相关输入发生变化的情况下重新计算剩余项。

为了补充@dtabuenc的答案,下面是一个如何防止在每次微小变化时触发该函数的示例:

替换:

<span>{{remaining()}} of {{todos.length}} remaining</span> [ <a href="" ng-click="archive()">archive</a> ]

这将防止angular对视图中的
remaining()。对任何输入更改触发$digest cycle每次更改绑定到输入的模型时,angular都会调用$disgest循环来更新模型和绑定。您已经绑定了todos变量和剩余的函数。在这种情况下调用此函数是正常的。可能的重复项您可能希望使用$watchCollection而不是标准的$watch
<span>{{remaining}} of {{todos.length}} remaining</span> [ <a href="" ng-click="archive()">archive</a> ]
$scope.$watch('todos', function(todos) {
  var count = 0;
  angular.forEach(todos, function(todo) {
    count += todo.done ? 0 : 1;
  }
  $scope.remaining = count;
}