在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])
});
答案 0 :(得分:34)
Angular为每个组件创建一个更改检测器对象(请参阅ChangeDetectorRef),该对象跟踪每个模板绑定的最后一个值,例如{{service.a}}
。默认情况下,在每个异步浏览器事件(例如来自服务器的响应,或单击事件或超时事件)之后,执行角度更改检测并使用这些更改检测器对象脏检查每个绑定。
如果检测到更改,则会传播更改。如,
{{}}
绑定值发生更改,则新值将传播到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?
答案 1 :(得分:17)
更改是作为反应发生的,因此在这方面它们是异步的。它们是由异步操作引起的,在浏览器世界中是Events。拦截那些事件角度使用zone.js,它修补JavaScript调用堆栈(我相信,有人纠正我,如果我错了)并暴露可以用来采取其他行动的钩子。
function angular() {...}
zone.run(angular);
如果你想象这个angular
函数是整个Angular,那就是它在区域中的运行方式。通过这样做可以拦截事件,如果它们被触发,我们可以假设发生了变化,并倾听/观察它们。
实际上ApplicationRef
会创建区域:
/**
* Create an Angular zone.
*/
export function createNgZone(): NgZone {
return new NgZone({enableLongStackTrace: assertionsEnabled()});
}
和类NgZone
是使用few event emitters创建的:
this._onTurnStartEvents = new EventEmitter(false);
this._onTurnDoneEvents = new EventEmitter(false);
this._onEventDoneEvents = new EventEmitter(false);
this._onErrorEvents = new EventEmitter(false);
它通过吸气剂暴露给外界:
get onTurnStart(): /* Subject */ any { return this._onTurnStartEvents; }
get onTurnDone() { return this._onTurnDoneEvents; }
get onEventDone() { return this._onEventDoneEvents; }
get onError() { return this._onErrorEvents; }
当ApplicationRef
为created时,它会订阅该区域的活动,特别是onTurnDone()
:
this.zone.onTurnDone
.subscribe(() => this.zone.run(() => this.tick());
当触发事件时,运行tick()
函数,循环遍历每个组件:
this._changeDetectorRefs.forEach((detector) => detector.detectChanges());
和detects changes基于组件“ChangeDetectionStrategy
。这些更改将作为SimpleChange
个对象的数组收集:
addChange(changes: {[key: string]: any}, oldValue: any, newValue: any): {[key: string]: any} {
if (isBlank(changes)) {
changes = {};
}
changes[this._currentBinding().name] = ChangeDetectionUtil.simpleChange(oldValue, newValue);
return changes;
}
通过onChanges
界面,我们可以使用
export interface OnChanges {
ngOnChanges(changes: {[key: string]: SimpleChange});
}