angularjs中的$watch、$digest、$apply

1、$watch($watch list):监视队列,在angularjs中每当我们向view上绑定数据时,就会往$watch中加入一条数据,用以监视数据有无变化,注意只有绑定到view上的数据才会加入$watch队列,如:

  {{data}}、ng-model和ng-repeat等指令指定的数据会加入到$watch队列中去。

$watch是$scope的方法,我们可以用$watch()方法监视自己的数据有无变化,如: $scope.$watch("data",function(){ data++});$watch()方法接受两个参数,一个要监视的数据及一个回调函数,在此处每当我们的data发生变化时就会触发一次回调函数。

2、$digest(循环):当浏览器接受到angular context处理的事件时,当我们通过ng-blur等指令对应的函数来改变了$scope中的某条数据时,当调用了$scope.$digest()方法时或调用了$scope.$apply()时,$digest循环就会被触发,并不断循环检测$watch队列中的数据有无变化,如果检测到$watch中的某条数据发生了变化时$digest会暂时将它记录下来,并回头从新开始检测数据有无变化,直到$watch中的数据都无变化时再将记录到的变化统一做dom操作。

需要值得注意的是$digest循环如果超过的10次就会报错,并结束循环,这是为了避免发生死循环,所以我们在修改model中的数据时最好不要引起一系列的连锁反应。

3、$apply:只有在$apply范围内(angularjs的上下文)的model改变才会启动$digest循环,如果我们脱离了$apply的范围修改model中的数据那么只能将model中的数据修改掉而对应的view不会发生变化,如:

        angular.module("testModel",[]).controller("testController",function($scope){

          setTimeout(function(){

            $scope.testData="我在这里修改了testData!";

          },1000)  

      });

这样的操作实际是脱离了angularjs的上下文的,也就是不在$apply的范围内了,$digest循环没有启动;这样我们虽然能修改掉Model中的数据,但是页面上的view是不会有变化的;解决这个问题的办法就是手动启动一个$digest循环 既:

        angular.module("testModel",[]).controller("testController",function($scope){

                setTimeout(function(){

                  $scope.$apply(function(){

                    $scope.testData="这次能修改了view中的testData数据了!";

                  })

                },1000)  

         });

因为$apply是我们的$scope的一个函数,调用它就会强制执行一次$digest循环(如果当前正在执行$digest循环,那么就会抛出一个异常,这是我们不需要执行$apply的警告),所以能够让view中的数据发生变化。

那么看到这里我们会问$digest的循环最少会执行几次呢?其实$digest的循环最少也会执行两次,因为listener函数也可能会修改一个model中的数据,所以$digest不会只执行一次,在当前的循环结束后就算没有数据变化它也会在执行一次循环来检测是否有model发生变化,这是为了避免listener函数被执行时也可能会引起model变化。

原文地址:https://www.cnblogs.com/xiaosuzhijia/p/4870311.html