$watch 没有像预期的那样触发多次

$watch not firing as many times as expected

如果您更改它正在监视的变量 x 次,我希望 $watch 触发 x 次。在我放在一起的一个小例子中,我改变了变量 $scope.foo 的值 3 次,但是关联的 $watch 只运行一次......

<html>
  <head>
    <title></title>
    <script src="https://code.angularjs.org/1.3.8/angular.js"></script>
  </head>
  <body ng-app='myApp'>

    <div ng-controller='MyCtrl'></div>

    <script>
      var myApp = angular.module('myApp', []);

      myApp.controller('MyCtrl', function($scope) {
          $scope.$watch('foo', function(oldVal, newVal) {
              console.log(oldVal, newVal);
          });

          $scope.foo = "foo";
          $scope.foo = "bar";
          $scope.foo = "baz";
      });


    </script>
  </body>
</html>

谁能解释这是什么原因,或者我可以采取不同的方法来获得预期的结果?

我期待以下控制台输出:

undefined foo
foo bar
bar baz

但是得到...

baz baz

编辑:另一个例子

  myApp.controller('MyCtrl', function($scope, $timeout) {
      $scope.$watch('foo', function() {
          $scope.bar = 'bar';
      });

      $scope.foo = "foo";

      // now the value of $scope.foo has changed, I was expecting the $watch to have run at this point.
      // Apparently is has not because $scope.bar is still undefined. Accessing $scope.bar in a $timeout works, but is there a better way?
      console.log($scope.bar)
  });

angular 的变化太快了,$timeout 有效:

<html>
  <head>
    <title></title>
    <script src="https://code.angularjs.org/1.3.8/angular.js"></script>
  </head>
  <body ng-app='myApp'>

    <div ng-controller='MyCtrl'></div>

    <script>
      var myApp = angular.module('myApp', []);

      myApp.controller('MyCtrl', function($scope, $timeout) {
          $scope.$watch('foo', function(oldVal, newVal) {
              console.log(oldVal, newVal);
          });

          $scope.foo = "foo";
          $scope.foo = "bar";
          $scope.foo = "baz";
        
          $timeout(function(){
            $scope.foo = "foo";
          },0)        
          $timeout(function(){
            $scope.foo = "bar";
          },0)        
          $timeout(function(){
            $scope.foo = "baz";
          },0)
      });


    </script>
  </body>
</html>

How does AngularJS's $watch function work?

A $watch 只会在每个 angular $digest 周期中触发一次! (如果观看 属性 那是最简单的场景)。

您对 foo 所做的三项更改都发生在同一周期内。而angular会比较循环前后的值。

对于您的情况,您需要通过例如更改 $timeout.

中的值来触发新循环

编辑

对于您的示例,您可以这样做

myApp.controller('MyCtrl', function($scope) {
    $scope.foo = "foo";
    // run on controller init
    fooWatch();
    // watch for changes
    $scope.$watch('foo', fooWatch);

    function fooWatch() {
        $scope.bar = 'bar';
    }
});

因为 $digest 循环不是 运行 每次您更改范围内的变量(幸运的是)。

但是当你使用$timeout时它会被触发。

你的用例是什么?

顺便说一句,在控制器中使用 $watch 通常不是一个好习惯,而且很容易避免。