You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Only operations which are applied in the Angular execution context will benefit(受益) from Angular data-binding(数据绑定), exception handling, property watching, etc...
The $evalAsync queue is used to schedule work(安排任务) which needs to occur outside of current stack frame, but before the browser's view render. This is usually done with setTimeout(0), but the setTimeout(0) approach suffers from slowness and may cause view flickering since the browser renders the view after each event.
The $watch list is a set of expressions which may have changed since last iteration. If a change is detected then the $watch function is called which typically updates the DOM with the new value.
$watch list 是一系列表达式的集合,ng中将模型展示在view中的方式便是对模型的值添加一些watch,如ng-model、{{}}插值表达式,以及指令的赋值等,也包括在js中在scope上调用$watch方法来实现数据的监听,这些所有便构成了$watch list。
$digest done && before DOM render(脏检查结束,DOM渲染之前)
The $digest loop keeps iterating until the model stabilizes(模型稳定), which means that the $evalAsync queue is empty and the $watch list does not detect any changes.
一、开始
Integration with the browser event loop
1.wait(等待触发 )
上图的左侧上部分,浏览器的事件机制等待事件的触发来响应操作。
这里的事件包含用户的交互操作(click,mousemove等)、js内部通过浏览器的定时操作(setInterval,setTimeout)以及与服务器的交互(ajax);
2.emits(事件触发)&& callback executes(执行回调)
此时浏览器的事件机制被触发,注册在对应事件上的listener被执行,此时进入js的上下文执行环境,执行我们预设的操作。在angular的项目中,会在此时通过调用$apply(fn)方法进入自身的数据检查模式$digest,就是图中的右侧部分。
这里的fn通常是一些会引起模型变化的动作,如:DOM事件,XHR响应回调,浏览器location变化,计时器的回调等,这也就是angular为何要与浏览器的event loop相互作用的原因。
$apply方法会先执行fn,然后进入$rootScope的脏检查来保证数据的一致性。
通常ng已经将上述浏览器的动作加入了$apply中来实现数据绑定,这就是我们并没有明确的在代码中调用$apply却实现了数据绑定的原因,当然,你也可以手动调用$apply来明确的引起一轮angular的数据检查。
现在我们进入了$digest loop,如上图所示,这里面又内涵了两个小的loop。
$evalAsyncQueue loop
目前只理解到这个队列中的任务会在$digest期间确保执行,下文提到的$evalAsync方法正是这个队列的入口。
当我们进行了一些操作,并引起了数据的变化,需要借助$digest来同步数据,如果此时已经存在一个$digest,我们便可以使用$evalAsync方法来该操作添加到已经存在的循环中的evalAsyncQueue,达到同步数据的目的。
$watchList loop
$watch list 是一系列表达式的集合,ng中将模型展示在view中的方式便是对模型的值添加一些watch,如ng-model、{{}}插值表达式,以及指令的赋值等,也包括在js中在scope上调用$watch方法来实现数据的监听,这些所有便构成了$watch list。
$digest done && before DOM render(脏检查结束,DOM渲染之前)
$digest loop终止的条件便是$evalAsync queue为空和$watch不再变化,至此我们便可以重新渲染DOM。
3.browser re-rendering(DOM重新渲染)
至此,数据的改变便驱动了view层的变化。
二、深入
1.ng如何根据作用域解析并执行表达式,或执行函数
表达式的解析与执行,函数的执行必须与作用域联系起来,并且该动作可能会引起数据的变化。
$eval
Executes the expression on the current scope and returns the result.
在当前作用域中执行表达式并返回结果。
考虑到执行的动作可能会改变数据,所以需要配合别的动作来进入digest循环,来确保数据的一致性。
$evalAsync
Executes the expression on the current scope at a later point in time.
“稍后但很及时的”在当前作用域中执行表达式,ng在这个动作中整合了保证数据一致性的动作。
$rootScope.$digest()
来确保数据的一致性。2.ng中如何检查数据。
$digest是数据绑定的核心,可分为
3.与浏览器eventLoop的结合。
$apply用于响应eventloop的事件,并进入
$rootScope.$digest()
;$rootScope.$digest()
。$applyAsync用于处理多个$apply请求。
$rootScope.$apply(flushApplyAsync)
,并给applyAsyncId赋值来注册$apply的状态。关于$applyAsync方法以及applyAsyncQueue队列的用意,目前没有很好的理解,$digest循环中也会进行applyAsyncId的判断以及applyAsyncQueue队列的flush(冲刷);
三、总结
MVVM模式的核心在于数据驱动,所以,一切对应用状态的操作的出发点应该是操作数据,再通过框架对数据的处理,最后映射到应用的状态,就是页面中的DOM状态。而这个处理数据的核心操作便是$digest循环。
在项目中使用angular作为框架时,能整理出驱动整个应用状态流转的数据变化,那么,与angular的合作便很顺利了。
The text was updated successfully, but these errors were encountered: