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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20942930/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 19:40:44  来源:igfitidea点击:

Angular expressions in $watch trigger twice

javascriptangularjs

提问by joemaller

Why does this $watchfire twice when a simple comparison is passed as the watchExpression?

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

$scope.foo = 0;  // simple counter

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

The listener fires when the page loads, when foois 0, then once more (and only once more) when the value of foogoes above 4.

侦听器在页面加载时触发,当foois时触发0,然后当 的值foo超过 4时再触发一次(并且仅触发一次)。

Why does the listener fire when the page loads? And why doesn't it continue to fire when foois greater than 4?

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

I set up a simple plunkr to show what's happening: http://plnkr.co/edit/ghYRl9?p=preview

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

回答by joemaller

After re-reading the Angular $watch docsa few more times, I think I understand what's happening.

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

The listener is called only when the value from the current watchExpression and the previous call to watchExpression are not equal

仅当当前 watchExpression 的值与上一次调用 watchExpression 的值不相等时才调用侦听器

Angular tracks the value of the watchExpression foo > 4with each digest()loop. Because this evaluated to false until foowas greater than 4, the listener didn't fire. Likewise, after foowas greater than 4, the values Angular was comparing were both true. The only time it detected a change was when the evaluated expression crossed over.

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

Two values are passed to the $watchlistener function, the new value and the old one. Logging these values shows that the watchExpression is being evaluated, and Angular is looking for a change in those values.

两个值传递给$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

The reason the listener was called on page load is also documented:

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

After a watcher is registered with the scope, the listenerfn is called asynchronously (via $evalAsync) to initialize the watcher. In rare cases, this is undesirable because the listener is called when the result of watchExpressiondidn't change. To detect this scenario within the listenerfn, you can compare the newValand oldVal. If these two values are identical (===) then the listener was called due to initialization.

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

I updated the plunkrwith a second $watchthat evaluates the value of foointernally:

我用一秒钟更新了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