$ watch中的角度表达式触发两次

时间:2014-01-06 04:21:58

标签: javascript angularjs

当一个简单的比较作为watchExpression传递时,为什么这个$watch会触发两次?

$scope.foo = 0;  // simple counter

$scope.$watch('foo > 4', function() {
  console.log("foo is greater than 4: ", $scope.foo);
});

foo 0foo时,侦听器会触发,foo的值超过4时,会再次触发(仅一次)。

为什么侦听器会在页面加载时触发?当{{1}}大于4时,为什么不继续发射?

我设置了一个简单的plunkr来显示正在发生的事情:http://plnkr.co/edit/ghYRl9?p=preview

1 个答案:

答案 0 :(得分:23)

重新阅读Angular $watch docs几次之后,我想我明白了发生了什么。

  

只有当前watchExpression的值和之前对watchExpression的调用不相等时才会调用侦听器

Angular跟踪每个foo > 4循环的watchExpression digest()的值。因为在foo大于4之前评估为false,所以监听器不会触发。同样,在foo大于4之后,Angular比较的值都是正确的。它检测到变化的唯一时间是评估的表达式越过。

将两个值传递给$watch侦听器函数,新值和旧值。记录这些值表明正在评估watchExpression,而Angular正在寻找这些值的变化。

$scope.$watch('foo > 4', function(newVal, oldVal) {
  console.log("foo is greater than 4: ", $scope.foo, oldVal, newVal);
});

// foo is greater than 4:  5 true false

还记录了在页面加载时调用侦听器的原因:

  

在观察者注册范围后,listener fn被异步调用(通过$evalAsync)来初始化观察者。在极少数情况下,这是不合需要的,因为在watchExpression的结果没有改变时调用了监听器。要在listener fn中检测此方案,您可以比较newValoldVal。如果这两个值相同(===),则由于初始化而调用了侦听器。

我使用第二个$watch更新了plunkr,以便在内部评估foo的值:

$scope.$watch('foo', function(newVal, oldVal) {
  if ($scope.foo > 4) {
  console.log("foo is greater than 4: ", $scope.foo, newVal, oldVal);
  }
});

// foo is greater than 4:  5 5 4
// foo is greater than 4:  6 6 5
// foo is greater than 4:  7 7 6