zoukankan      html  css  js  c++  java
  • 深入理解angularjs $watch ,$apply 和 $digest --- 理解数据绑定过程

    转自:http://www.angularjs.cn/A0a6

    Angular用户都想知道数据绑定是怎么实现的。你可能会看到各种各样的词汇:$watch,$apply,$digest,dirty-checking... 它们是什么?它们是如何工作的呢?让我们从头开始吧。

    浏览器事件循环和Angular.js扩展

    我们的浏览器一直在等待事件,比如用户交互。假如你点击一个按钮或者在输入框里输入东西,事件的回调函数就会在javascript解释器里执行,然后你就可以做任何DOM操作,等回调函数执行完毕时,浏览器就会相应地对DOM做出变化。 Angular拓展了这个事件循环,生成一个有时成为angular context的执行环境(记住,这是个重要的概念),为了解释什么是context以及它如何工作,我们还需要解释更多的概念。

    $watch 队列($watch list)

    每次你绑定一些东西到你的UI上时你就会往$watch队列里插入一条$watch。想象一下$watch就是那个可以检测它监视的model里时候有变化的东西。例如你有如下的代码

    index.html

    User: <input type="text" ng-model="user" />
    Password: <input type="password" ng-model="pass" />

    在这里我们有个$scope.user,他被绑定在了第一个输入框上,还有个$scope.pass,它被绑定在了第二个输入框上,然后我们在$watch list里面加入两个$watch:

    controllers.js

    app.controller('MainCtrl', function($scope) {
      $scope.foo = "Foo";
      $scope.world = "World";
    });

    index.html

    Hello, {{ World }}

    这里,即便我们在$scope上添加了两个东西,但是只有一个绑定在了UI上,因此在这里只生成了一个$watch. 再看下面的例子: 

    index.html

    <ul>
      <li ng-repeat="person in people">
          {{person.name}} - {{person.age}}
      </li>
    </ul>

    这里又生成了多少个$watch呢?每个person有两个(一个name,一个age),然后ng-repeat又有一个,因此10个person一共是(2 * 10) +1,也就是说有21个$watch。 因此,每一个绑定到了UI上的数据都会生成一个$watch。对,那这写$watch是什么时候生成的呢? 当我们的模版加载完毕时,也就是在linking阶段(Angular分为compile阶段和linking阶段---译者注),Angular解释器会寻找每个directive,然后生成每个需要的$watch。听起来不错哈,但是,然后呢?

    $digest循环(这个digest不知道怎么翻译)

    还记得我前面提到的扩展的事件循环吗?当浏览器接收到可以被angular context处理的事件时,$digest循环就会触发。这个循环是由两个更小的循环组合起来的。一个处理evalAsync队列,另一个处理$watch队列,这个也是本篇博文的主题。 这个是处理什么的呢?$digest将会遍历我们的$watch,然后询问:

    • 嘿,$watch,你的值是什么?
      • 是9。
    • 好的,它改变过吗?
      • 没有,先生。
    • (这个变量没变过,那下一个)
    • 你呢,你的值是多少?
      • 报告,是Foo
    • 刚才改变过没?
      • 改变过,刚才是Bar
    • (很好,我们有DOM需要更新了)
    • 继续询问知道$watch队列都检查过。

    这就是所谓的dirty-checking

    例如: controllers.js

    app.controller('MainCtrl', function() {
      $scope.name = "Foo";
    
      $scope.changeFoo = function() {
          $scope.name = "Bar";
      }
    });

    index.html

    {{ name }}
    <button ng-click="changeFoo()">Change the name</button>

    这里我们有一个$watch因为ng-click不生成$watch(函数是不会变的)。

    • 我们按下按钮
    • 浏览器接收到一个事件,进入angular context(后面会解释为什么)。
    • $digest循环开始执行,查询每个$watch是否变化。
    • 由于监视$scope.name$watch报告了变化,它会强制再执行一次$digest循环。
    • 新的$digest循环没有检测到变化。
    • 浏览器拿回控制权,更新与$scope.name新值相应部分的DOM。

    这里很重要的(也是许多人的很蛋疼的地方)是每一个进入angular context的事件都会执行一个$digest循环,也就是说每次我们输入一个字母循环都会检查整个页面的所有$watch

    通过$apply来进入angular context

    谁决定什么事件进入angular context,而哪些又不进入呢?$apply

    如果当事件触发时,你调用$apply,它会进入angular context,如果没有调用就不会进入。现在你可能会问:刚才的例子里我也没有调用$apply啊,为什么?Angular为了做了!因此你点击带有ng-click的元素时,时间就会被封装到一个$apply调用。如果你有一个ng-model="foo"的输入框,然后你敲一个f,事件就会这样调用$apply("foo = 'f';")

    后文见下一篇文章!

  • 相关阅读:
    Finding Action Tubes
    Modeling Video Evolution For Action Recognition
    GBrank_问题列表
    annotation code for human pose estimation
    什么是 kNN 算法?
    什么是强化学习?
    什么是张量?
    什么是遗传/进化算法?
    什么是贝叶斯网络?
    什么是机器学习?
  • 原文地址:https://www.cnblogs.com/bonelee/p/6100960.html
Copyright © 2011-2022 走看看