在Angular 1中,更改检测是通过脏检查$ scope层次结构 . 我们会在模板,控制器或组件中隐式或明确地创建观察者 .
在Angular 2中,我们不再有$ scope,但我们覆盖了setInterval,setTimeout等 . 我可以看到Angular如何使用它来触发$ digest,但是Angular如何确定改变了什么,特别是考虑到Object.observe从未进入浏览器?
示例
这是一个简单的例子 . 服务中定义的对象在setInterval中更新 . 每个间隔重新编译DOM .
Angular如何能够告诉AppComponent正在观看该服务,以及该服务属性的值是否已经改变?
var InjectedService = function() {
var val = {a:1}
setInterval(() => val.a++, 1000);
return val;
}
var AppComponent = ng.core
.Component({
selector: "app",
template:
`
{{service.a}}
`
})
.Class({
constructor: function(service) {
this.service = service;
}
})
AppComponent.parameters = [ new ng.core.Inject( InjectedService ) ];
document.addEventListener('DOMContentLoaded', function() {
ng.platform.browser.bootstrap(AppComponent, [InjectedService])
});
2 回答
Angular为每个组件创建一个更改检测器对象(请参阅ChangeDetectorRef),该对象跟踪每个模板绑定的最后一个值,例如
{{service.a}}
. 默认情况下,在每个异步浏览器事件(例如来自服务器的响应,或单击事件或超时事件)之后,角度更改检测执行并使用这些更改检测器对象脏检查每个绑定 .如果检测到更改,则传播更改 . 例如 . ,
如果输入属性值已更改,则新值将传播到组件的input属性 .
如果
{{}}
绑定值发生更改,则新值将传播到DOM属性textContent
.如果在样式,属性或类
x
的值发生变化的结合 - 即[style.x]
或[attr.x]
或[class.x]
- 新值被传播到DOM来更新样式,HTML属性,或类 .Angular使用Zone.js创建自己的区域(NgZone),该区域修补所有异步事件(浏览器DOM事件,超时,AJAX / XHR) . 这是变更检测能够在每个异步事件之后自动运行的方式 . 即,在每个异步事件处理程序(函数)完成之后,将执行角度变化检测 .
我在这个答案中有更多的细节和参考链接:What is the Angular2 equivalent to an AngularJS $watch?
Zone.js
变化是对事物的反应而发生的,因此在这方面它们是异步的 . 它们是由异步操作引起的,而在浏览器世界中则是Events . 为了拦截那些事件,角度使用了zone.js,它修补了JavaScript调用堆栈(我相信,有人纠正我,如果我错了)并暴露可以用来采取其他行动的钩子 .
如果你想象这个
angular
函数是整个Angular,那就是它在区域中的运行方式 . 通过这样做 Events 可以被截获,如果它们被触发,我们可以假设发生变化,并倾听/观察它们 .ApplicationRef
实际上ApplicationRef创建了区域:
和
NgZone
类是使用few event emitters创建的:它通过吸气剂暴露给外界:
当
ApplicationRef
是created时,它订阅了区域的事件,特别是onTurnDone()
:更改
当事件被触发时,运行tick()函数,循环遍历每个组件:
和detects changes基于组件'
ChangeDetectionStrategy
. 这些更改将作为SimpleChange对象的数组收集:巫婆可通过onChanges界面获取: