如果已经存在,Angular会创建一个新的观察者吗?

Ada*_*ner 9 angularjs

考虑:

angular
  .module('app', [])
  .controller('MainController', function($scope) {
    $scope.$watch('bool', function(newVal, oldVal) {
    });
    console.log($scope);
  });
Run Code Online (Sandbox Code Playgroud)

<body ng-controller='MainController'>
  <p ng-class="{'blue': bool, 'red': !bool}">ngClass</p>
  <p ng-show='bool'>ngShow</p>
  <input type='checkbox' ng-model='bool' />
</body>
Run Code Online (Sandbox Code Playgroud)

上面的plnkr

似乎有3名观察者被创建:

  1. 来自$scope.$watch.
  2. 来自ngShow.
  3. 来自ngClass.

(注意:数据绑定中涉及的指令使用 $ scope.$ watch内部.)

在此输入图像描述

我原本以为,因为他们都在看bool房子,所以只有一个观察者,并且它有多个听众回调.


编辑:它是否说,"已经bool改变?如果是这样的话cb1.已经bool改变了?如果是这样的话cb2.已经bool改变了?如果是这样的话cb3." 或者是它的情况下,它的话说,"已经bool改变了吗?如果是这样运行的cb1,cb2cb3".如果是前者,为什么会这样呢?

问题:

  1. 我的解释是否正确?实际上是否有多个手表被注册?
  2. 对性能有何影响?
  3. 奖励:如果我的解释是正确的并且正在添加多个观察者,为什么会这样设计呢?为什么要寻找bool3次而不是1次的变化?

示例2) - 假设您要确保表单中的两个密码匹配,如果不匹配,则显示错误.假设你已经拥有:

ng-class="{invalid: myForm.myInput1.$touched && ctrl.myInput1  != ctrl.myInput2}" 
Run Code Online (Sandbox Code Playgroud)

假设您要使用$setValidity更新表单的有效性.这可能是个好主意:

ng-class="{invalid: myForm.myInput1.$touched && ctrl.functionToCheckInputs(myForm)}"
Run Code Online (Sandbox Code Playgroud)

并调用$setValidity内部functionToCheckInputs而不是使用$scope.$watch$setValidity内部做?因为后者增加了额外的观察者(大概).

New*_*Dev 3

有多个 $watchers 正在注册。事实上,即使你有 2 个精确的表达式:

$scope.$watch("foo", cb1)
$scope.$watch("foo", cb2)
Run Code Online (Sandbox Code Playgroud)

你仍然会得到 2 $watchers。

回答你的问题 - 这是前一种情况,即“如果"foo"表达式改变,运行cb1,如果"foo"表达式改变,运行cb2,等等...为什么?因为,任何 $watcher 都可能改变 ; 的返回值$scope.foo,而不仅仅是在回调中,但在表达式本身中,Angular 需要每次都重新评估表达式以考虑这种可能性。

摘要周期的长度对性能起着重要作用。

首先是 $watchers 的数量,它会导致监视的表达式或函数进行计算。因此,减少 $watchers 的数量,例如更喜欢单向监视而不是双向监视,或者在合适的情况下使用一次性监视,可以提高性能。

其次,是观看功能的复杂性。这些函数应该非常快——理想情况下,不超过 getters。例如,避免以下情况:

<div ng-class="{active: isActive(id)}">
Run Code Online (Sandbox Code Playgroud)
$scope.isActive = function(id){
   for (var i=0; i<items.length; i++){
      if (items[i].id == id && items[0].active) return true;
   }
   return false;
};
Run Code Online (Sandbox Code Playgroud)