angular 双向数据绑定原理

要理解angular双向数据绑定,首先要理解js的事件轮询---event-loop;

JavaScript 运行机制详解:再谈Event Loop 这篇文章介绍的不错;

123215_XKso_782865.png

理解了以上内容之后就可以看下面这个文章;

angular何为作用域(Scope)

与浏览器事件轮循整合

02123449_C2Wt.png

下图与示例描述了Angular如何与浏览器事件轮循进行交互。

  1. 浏览器的事件轮循等待事件到来,事件可以是用户交互,定时器事件,或是网络事件(如 ajax 返回)

  2. 事件发生,其回调被执行,回调的执行就使得应用程序的执行上下文进入到了 JavaScript 的上下文。然后在 JavaScript的上下文中执行,并修改相关的DOM结构

  3. 一旦回调执行完毕,浏览器就离开 JavaScript的上下文回到浏览器上下文并基于DOM结构的改变重新渲染视图

讲了那么多些,那么Angular是怎么在这里横插一杠呢?看图,Angular是插进了 JavaScript的上下文中,通过提供Angular自己的事件处理轮循来改变正常的JavaScript工作流。它其实是把JavaScript上下文很成了两块:一个是传统的JavaScript执行上下文(图中浅蓝色区域),一个是Angular的执行上下文(图中淡黄色区域)。 只有在Angular上下文执行的操作才会受益于Angular的数据绑定,异常处理,属性检测,等等。当然,如果不在Angular的上下文中,你也可以使用 $apply() 来进入Angular的执行上下文。 需要注意的是,$apply() 在Angular本身的很多地方(如控制器,服务等)都已经被隐式地调用了来处理事件轮循。 显示地使用 $apply() 只有在你从 JavaScript上下文或是从第三方类库的回调中想要进入Angular时才需要。让我们来看看具体的流程:

  1. 进入Angular执行上下文的方法,调用 scope.$apply(stimulusFn) 。上面 $apply() 中的参数 stimulusFn 是你想要让它进入Angular上下文的代码

  2. 进入 $apply() 之后,Angular执行 stimulusFn() ,而这个函数通常会改变应用程序的状态(可能是数据,或是方法调用等)

  3. 之后,Angular进入 $digest 轮循。这个轮循是由两个较小的轮循构成,一个是处理 $evalAsync 队列(异步计算的队列),另一个是处理 $watch 列表。 $digest 轮循不断迭代变更(在 $eval 和 $watch 之间变更)直到数据模型稳定,这个状态其实就是evalAsync 队列为空且$watch 列表不再监测到变化为止。(译注:其实这里就是所有外来的异步操作堆起来成为一个队列,由$eval一个个计算,然后 $watch 看一下这个异步操作对应的数据模型是否还有改变,有改变,就继续 $eval 这个异步操作,如果没改变,那就拿异步操作队列里的下个异步操作重复上述步骤,直到异步操作队列为空以及 $watch 不再监测到任何数据模型变化为止)

  4. $evalAsync 队列是用来安排那些待进入Angular$digest 的异步操作,这些操作往往是在浏览器的视图渲染之前,且常常是通过setTimeout(0) 触发。但是用 setTimeout(0) 这个方法就不得不承受缓慢迟钝的响应以及可能引起的闪屏(因为浏览器在每次事件发生后都会渲染一次)(译注:这里个人觉得不要理解的太复杂,按照上面第三点理解就够用了,这边个人翻译的也不是太好,后期配以例子完善)

  5. $watch 列表则是存放了一组经过 $eval 迭代之后可能会改变的Angular的表达式集合。如果数据模型变化被监测到,那么 $watch 函数被调用进而用新值更新DOM。

  6. 一旦Angular的 $digest 轮循完成,那么应用程序的执行就会离开Angular及 JavaScript的上下文。然后浏览器重新渲染DOM来反映发生的变化

接下来是传统的 Hello world 示例(就是本节的第一个例子)的流程剖析,这样你应该就能明白整个例子是如何在用户输入时产生双向绑定的。

  1. 编译阶段:

    1. ng-model 和 input 指令 在 <input> 标签中设置了一个 keydown 监听器

    2. {{greeting}} 插值(也就是表达式)这里设置了一个 $watch 来监测 username 的变化

  2. 执行阶段:

    1. 在 <input> 输入框中按下 'X' 键引起浏览器发出一个 keydown 事件

    2. input 指令捕捉到输入值的改变调用 $apply("username = 'X';") 进入Angular的执行环境来更新应用的数据模型

    3. Angular将 username = 'X'; 作用在数据模型之上,这样 scope.username 就被赋值为 'X' 了

    4. $digest 轮循开始

    5. $watch 列表中监测到 username 有一个变化,然后通知 {{greeting}} 插值表达式,进而更新DOM

    6. 执行离开Angular的上下文,进而 keydown 事件结束,然后执行也就退出了 JavaScript的上下文;这样 $digest 完成

    7. 浏览器用更新了的值重新渲染视图

转载于:https://my.oschina.net/u/782865/blog/513188

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值