脏检查及其优点

什么是脏检查

脏检查即一种不关心你如何以及何时改变的数据, 只关心在特定的检查阶段数据是否改变的数据监听技术.

本节包含内容

  • 什么是脏检查
  • 脏检查是如何进行的
  • 何时进行脏检查
  • regularjs为何选择脏检查

这里会统一使用angularjs生态圈的术语,方便开发者理解

相信对于熟悉angularjs的开发者而言, 脏检查这个概念不会太陌生.

以插值{post.title}为例, 当regularjs在compile阶段遇到这个语法数元素时, 内部的处理逻辑如下.

 
  1.  
  2. walkers.expression = function( ast ){

  3. var node = document.createTextNode("");

  4. this.$watch(ast, function(newval){

  5. dom.text(node, "" + (newval == null? "": "" + newval) );

  6. })

  7. return node;

  8. }

这段代码很好理解,即遇到插值时,我会创建一个textNode, 每当数据变化时,修改textNode的textContent值.

其中

  • ast: 表达式: 即post.title, 反映在组件就是component.data.post.title.
  • $watch: 添加一个数据监听器(watcher对象)

那么问题来了, 怎么判断值发生改变了?

脏检查如何进行? 不提不提的Digest阶段

首先, 上例通过$watch接口产生的watcher对象看起来是这样的

 
  1.  
  2. {

  3. get: function(context){...} //获得表达式当前求值, 此函数在解析时,已经生成

  4. set: function(){} // 有些表达式可以生成set函数, 用于处理赋值, 这个一般用于双向绑定的场景

  5. once: false // 此监听器是否只生效一次

  6. last: undefined// 上一次表达式的求值结果

  7. fn: function(newvalue, oldvalue){} // 即你传入$watch的第二个参数, 当值改变时, 会调用此函数

  8. // ...

  9. }

然后我们要提到内部的一个非常重要的阶段——digest阶段, 当系统进入此阶段时,将会进行数据检查, 它的处理流程如下:

  1. 标记dirty = false
  2. 遍历所有通过component.$watch绑定的数据观察者watcher, 对比当前值watcher.get(component)与老值watcher.last
    • 如果值发生改变, 运行绑定的监听器 - watcher.fn(newvalue, oldvalue), 并导致__dirty__=true. 设置watcher.last=newvalue
    • 进入下一个watcher的检查
  3. 遍历检查一轮后, 如果dirty===true, 我们重新进入步骤1. 否则进入步骤4.
  4. 完成脏检查

好, 现在我们了解数据检查的内部流程了, 但是何时进入digest阶段

何时进行脏检查

有基本的javascript基础的同学都知道, 在姗姗不来的ES7Object.observe方法没有到来时(但是别对Object.observe抱太大得期望, 它不会改变目前类mvvm框架的格局, 我后续会写一篇文章说明), 当我们对对象属性进行赋值时, 我们是无法知道数据发生改变了的, 所以digest阶段必然是 主动进入的 .

在regularjs中, digest阶段是由$update方法触发的.

Example

 
  1. var component = new Regular();

  2.  
  3. component.data.name = 'leeluolee'

  4.  
  5. // you need call $update to Synchronize data and view

  6. component.$update();

值得庆幸的是,大部分情况下都会自动进入digest阶段.比如事件、timeout模块等等.

<div on-click={blog.title='Hello'}>{blog.title}</div>

当点击节点后, 内容区会变成Hello.

题外话: 为什么使用脏检查

  1. 脏检查完全不关心你改变数据的方式, 而常规的set, get的方式则会强加许多限制
  2. 脏检查可以实现批处理完数据之后,再去统一更新view.
  3. 脏检查其实比 GET/SET 更容易实现. 脏检查是个单向的检查流程(请不要和双向绑定发生混淆), 可以实现任意复杂度的表达式支持. 而get/set的方式则需要处理复杂依赖链 , 基本上表达式支持都是阉割的(使用时就像踩雷).

但是很显然, 脏检查是低效的, 它的效率基本上取决于你绑定的观察者数量, 在regularjs中, 你可以通过@(Expression)元素来控制你的观察者数量.

然而结合这种类mvvm系统中, 他又是高效的. 因为监听模式带来了dom的局部更新, 而dom操作恰恰又是隐藏的性能瓶颈所在.

regularjs实际上在解析时,已经提取了表达式的依赖关系, 在未来Observe到来时, 可以调整为脏检查 + 依赖计算的方式。

 

文章来源:http://www.phperz.com/article/15/0906/154484.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值