AngularJS双向数据绑定原理中$watch、$apply和$digest的应用
介绍
这篇文章是为AngularJS的初学者准备的。如果你对AngularJS的双向数据绑定有很深的理解,直接阅读源代码就可以了。
背景
AngularJS开发人员想知道如何实现双向数据绑定。有许多与数据绑定相关的术语:观察、应用、摘要、脏检查等。它们是如何工作的?让我们从头开始
AngularJS的双向数据绑定是浏览器强制的
浏览器看起来很漂亮。事实上,在数据交互领域,浏览器的“不作为”使得浏览器的数据刷新成为一个难题。具体来说,浏览器可以很容易的监听到一个事件,比如:用户点击一个按钮或者在输入框中输入一些东西,并为事件回调函数提供了一个API,这个API会在javascript解释器中执行;相反,事情没那么简单。如果后台的数据发生变化,需要通知浏览器进行刷新。浏览器没有提供这样的数据交互机制,这对开发者来说是不可逾越的障碍。我该怎么办?AngularJS应运而生,它通过$scope实现了双向数据绑定。背后的原则是$ watch、$ apply、$ digest、脏检查
$ watch queue($观察列表)
从字面上看,观察意味着观察。每次有东西绑定到浏览器时,一个$watch就会被插入到$watch队列中。想象一下,$watch是可以检测到它所监控的模型变化的东西。例如,您有以下代码
User:输入类型=' text ' ng-model=' user '/password :输入类型=' password ' ng-model=' pass '/有一个$scope.user绑定到第一个输入框,有一个$scope.pass绑定到第二个输入框。然后在$watch列表中添加两个$watch:
使用以下代码创建一个controllers.js文件:
app.controller('MainCtrl ',function($ scope){ $ scope . Foo=' Foo ';$ scope.world=' World});对应的html文件,index.html代码如下:
您好,{{ World }}在这里,即使在$scope中添加了两个东西,也只有一个绑定到UI,所以只生成一个$watch。请看下面的例子:
controllers.js
app.controller('MainCtrl ',function($ scope){ $ scope . people=[.];});对应的html文件index.html
ul Li ng-repeat=' person in people ' { person。姓名} }-{ {人。age}}/Li/ul这样,就生成了几块$ watches。每个人有两个(一个名字,一个年龄),然后ng-repeat是一个循环,所以10个人的总数是(2 * 10) 1,这意味着有21美元的手表。因此,绑定到浏览器的每个数据都会生成一个$watch。对,这里写的$watch是什么时候产生的?首先,回顾AngularJS的加载原理
AngularJS的加载原理:
AngularJS的模板加载分为编译和链接两个阶段。在链接阶段,AngularJS解释器将查找每个指令,然后生成每个所需的$watch。顺便说一下,$watch就是在这个阶段生成的。
接下来,我们开始使用$digest
$digest循环
从字面上来说,消化就是“消化”,总感觉怪怪的。就像脏检查一样奇怪,字面意思是“脏检查”。最好不要翻译。原作者的本意绝对不是这个意思,而是只能用文字来理解!
$digest是一个循环。它在循环中做什么?$digest正在遍历我们的$watch。$digest逐个询问$watch ——,“嘿,你观察到的数据有变化吗?”
这种遍历称为脏检查。既然$手表都检查过了,那就有必要问一下:你更新过$手表了吗?如果至少更新了一个,将再次触发此循环,直到所有$ watches都没有更改。这样就可以保证每一款车型都不会再有变化。请记住,如果循环超过10次,它将引发异常以避免无限循环。当$digest循环结束时,DOM会相应地改变。
看看代码,例如:controllers.js
app.controller('MainCtrl ',function(){ $ scope . name=' Foo ';$ scope . changefooo=function(){ $ scope . name=' Bar ';}});对应的html文件,index.html
{ { name } } button ng-click=' change foo()'更改名称/button这里只有一个$watch,因为ng-click不会生成$watch(函数不会更改)。
$digest执行的过程是:
按浏览器中的按钮;浏览器接收一个事件并输入角度上下文。$digest循环开始执行,并查询每个$watch是否改变。由于$watch monitoring $scope.name报告了该更改,它将强制执行另一个$digest循环。在新的$digest循环中没有检测到变化,此时浏览器收回控制权,更新与$ scope.name新值对应的DOM,我们可以看到AngularJS的一个明显不足:每个进入angular context的事件都会执行一个$digest循环,即使只输入一个字母,$digest也会遍历整个页面的所有$ watches。
$apply的应用
角度上下文是整个角度上下文,也可以理解为一个角度容器。那么,谁来决定哪些事件可以进入Angular上下文,哪些事件不能?它的控制者掌握在$apply手中。
如果在事件被触发时调用$apply,它将进入angular context,但是如果不调用它,它将不会进入。你可能会问:刚才的例子没有叫$apply,发生了什么?原来是Angular为你做的。当单击带有ng-click的元素时,事件被封装在$apply调用中。如果有一个带有ng-model='foo '的输入框,当输入字母f时,事件将被这样调用,$ apply(' foo=' f ';')。
$apply的应用场景
$apply是$scope的函数,调用它将强制执行$digest循环。如果$apply循环当前正在执行,将引发异常。
如果浏览器上的数据没有及时刷新,可以通过调用$scope强制刷新。$apply()方法。
通过$watch监控您自己的$scope
!DOCTYPE html html ng-app=' Demoapp ' head title test/title!-供应商库-脚本src=' http : lib/jquery-v 1 . 11 . 1 . js '/脚本脚本src=' http : lib/angular-v 1 . 2 . 22 . js '/脚本脚本脚本src=' http : lib/angular-route-v 1 . 2 . 22 . js '/脚本/流浆池div ng-controller=' MainCtrl ' input ng-model=' Name '/Name updated : { { updated } }次。/div脚本var Demoapp=angular . module(' Demoapp ',[]);demoApp.controller('MainCtrl ',function($ scope){ $ scope . name=' Angular ';$ scope . updated=-1;$scope。$watch('name ',function(){ $ scope . updated;});});/script /body/html代码描述:
当控制器执行$watch时,将立即调用一次,因此将更新后的值设置为-1。当上方输入框中输入的字符发生变化时,您会看到更新后的值随之变化,并且可以显示变化的次数。
$watch检测到数据更改
摘要
我们对AngularJS的双向数据绑定有了初步的了解。对于AngularJS来说,表面上操作DOM很简单,但实际上,$watch,$digest,$apply都在默默发挥作用。这种检查数据是否已经改变的遍历过程称为脏检查。当你理解了这个过程,你会冷笑,觉得这个方法好低级。的确,如果一个DOM中有2000- 3000个watch,页面渲染速度会大大降低。
如何解决这个渲染性能问题?随着ECMAScript6的出现,Angular 2大大提高了$digest循环通过Object的速度。观察也许这就是Angular团队迫不及待地推出Angular 2的原因。
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。
版权声明:AngularJS双向数据绑定原理中$watch、$apply和$digest的应用是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。