此外,在生成的类中,我没有看到它被用于除简单通知之外的其他内容:
conmponent / wrapper.ngfactory.js
Wrapper_AppComponent.prototype.ngDoCheck = function(view,el,throwOnChange) { var self = this; var changed = self._changed; self._changed = false; if (!throwOnChange) { if (changed) { jit_setBindingDebugInfoForChanges1(view.renderer,self._changes); self._changes = {}; } self.context.ngDoCheck(); <----------- this calls ngDoCheck on the component but the result is not used anywhere and no params are passed } return changed; };
ngDoCheck
means your component is being checked — read this article深入解释了错误。
此答案的内容基于角度版本2.x.x.对于最新版本4.x.x,请参阅this post。
互联网上没有关于变更检测内部工作的任何内容,因此我不得不花费大约一周的时间来调试源代码,因此这个答案对于细节来说将是非常技术性的。
角度应用程序是views的树(AppView类由编译器生成的Component特定类扩展)。每个视图都有一个更改检测模式,该模式位于cdMode属性中。 cdMode的默认值是ChangeDetectorStatus.CheckAlways,即cdMode = 2。
运行更改检测周期时,每个父视图都会检查是否应对子视图here执行更改检测:
detectChanges(throwOnChange: boolean): void { const s = _scope_check(this.clazz); if (this.cdMode === ChangeDetectorStatus.Checked || this.cdMode === ChangeDetectorStatus.Errored) return; if (this.cdMode === ChangeDetectorStatus.Destroyed) { this.throwDestroyedError('detectChanges'); } this.detectChangesInternal(throwOnChange); <---- performs CD on child view
这指向子视图。因此,如果cdMode是ChangeDetectorStatus.Checked = 1,则由于此行而跳过针对直接子节点及其所有后代的更改检测。
if (this.cdMode === ChangeDetectorStatus.Checked || this.cdMode === ChangeDetectorStatus.Errored) return;
什么changeDetection:ChangeDetectionStrategy.OnPush做的只是将cdMode设置为ChangeDetectorStatus.CheckOnce = 0,所以在第一次更改检测后,子视图的cdMode将因为this code而设置为ChangeDetectorStatus.Checked = 1:
if (this.cdMode === ChangeDetectorStatus.CheckOnce) this.cdMode = ChangeDetectorStatus.Checked;
这意味着下次更改检测周期开始时,不会对子视图执行更改检测。
如何为此类视图运行更改检测的选项很少。首先是将子视图的cdMode更改为ChangeDetectorStatus.CheckOnce,这可以使用ngDoCheck生命周期钩子中的this._changeRef.markForCheck()来完成:
constructor(private _changeRef: ChangeDetectorRef) { } ngDoCheck() { this._changeRef.markForCheck(); }
这只是将当前视图及其父项的cdMode更改为ChangeDetectorStatus.CheckOnce,因此下次执行更改检测时,将检查当前视图。
查看完整的示例here in the sources,但这是它的要点:
constructor(ref: ChangeDetectorRef) { setInterval(() => { this.numberOfTicks ++ // the following is required,otherwise the view will not be updated this.ref.markForCheck(); ^^^^^^^^^^^^^^^^^^^^^^^^ },1000); }
第二个选项是在视图本身上调用detectChanges,如果cdMode不是ChangeDetectorStatus.Checked或ChangeDetectorStatus.Errored,则在当前视图上调用run change detection。由于使用onPush角度将cdMode设置为ChangeDetectorStatus.CheckOnce,angular将运行更改检测。
因此,ngDoCheck不会覆盖已更改的检测,只需在每个更改的检测周期调用它,并且唯一的工作是将当前视图cdMode设置为checkOnce,以便在下一个更改检测周期中检查更改。有关详细信息,请参阅this answer。如果当前视图的更改检测模式为checkAlways(如果未使用onPush策略,则默认设置),ngDocCheck似乎没用。