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

joe*_*ler 14 javascript angularjs

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

$scope.foo = 0;  // simple counter

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

当页面加载时,当收听者的火灾foo0,则一次(且仅一次)时的值foo变得高于4.

为什么在页面加载时监听器会触发?当foo大于4 时为什么不继续发射?

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

joe*_*ler 23

在重新阅读Angular $ watch文档几次之后,我想我明白了发生了什么.

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

Angular跟踪foo > 4每个digest()循环的watchExpression的值.因为这被评估为假,直到foo大于4,所以听众没有开火.同样,在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
Run Code Online (Sandbox Code Playgroud)

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

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

我用第二个更新了plunkr$watch来评估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
Run Code Online (Sandbox Code Playgroud)

  • 只是为了补充一点,我发现评估你的特定条件(> 4)总是更好*里面的*$ watch`回调(正如你在上一个代码片段中所做的那样),因为能够检查是否有价值通常是有价值的. `$ scope`属性实际上有一个值(`newVal!= null`),如果它改变了(`!angular.equals(newVal,oldVal)`). (4认同)