当一个简单的比较作为watchExpression传递时,为什么这个$watch
会触发两次?
$scope.foo = 0; // simple counter
$scope.$watch('foo > 4', function() {
console.log("foo is greater than 4: ", $scope.foo);
});
当foo
0
为foo
时,侦听器会触发,foo
的值超过4时,会再次触发(仅一次)。
为什么侦听器会在页面加载时触发?当{{1}}大于4时,为什么不继续发射?
我设置了一个简单的plunkr来显示正在发生的事情:http://plnkr.co/edit/ghYRl9?p=preview
答案 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中检测此方案,您可以比较newVal
和oldVal
。如果这两个值相同(===
),则由于初始化而调用了侦听器。
我使用第二个$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