数据双向绑定
在VUE中,通过ES5提供的getter和setter实现单向数据流。而在Angular中通过所谓的脏值查询实现了双向数据绑定,即View层和ViewModel层的双向数据流。具体是如何做到的呢。
基本原理
首先我们要了解订阅-发布模式(原理见我的另一篇博文EVENT事件库的原理)。Angular的脏值查询在此基础上实现。
这里我们先构建作用域构造函数,并设置事件池
数据变动的检测基于$scope作用域两个内置方法$watch和$digest。$watch类似事件库里的on方法,用于在事件池(在Angular中是作用域中的$$watchers属性)中存放事件名和对应回调函数。
类似这样
- watchFn 为监控函数,返回所监控的数据的值
- listenerFn 为监听函数,当数据发生变化后作出行为
一个监控name值的简单监控函数1234//监控作用域中name属性的值function (scope) {return scope.name;}
$digest类似事件库中的emit方法,用来执行所在作用域中事件池($$watchers数组)中保存的方法对应的回调函数(即数据的监听函数),并把执行后新的值保存在$watch中。这样我们再次调用$digest,就能比较新值与旧值的变化。
类似这样
这就是Angular作用域的本质:添加监听器,在$digest中运行他们。
这也揭示了Angular作用域的性能特性:
- 在作用域中添加数据并不会带来性能折扣。Angular并不会遍历作用域的数据,只会遍历绑定在$$watchers中的事件。
- $digest会调用每个监控函数。因此,最好关注监听器的数量,还有每个独立的监控函数或者表达式的性能。
存在的问题
现在我们的脏值检查还存在很多问题,其中比较重要的一个应用场景咱们就没有实现——当监听函数自身也修改作用域上的属性。如果这个发生了,另外有个监听器在监控被修改的属性,有可能在同一个digest里面检测不到这个变动。