4

我有一个一般的 Angular 问题:

为什么 Angularasync管道使用cdr.markForCheck()而不是cdr.detectChanges()

我看到这两种“风格”有两个主要区别:

  1. markForCheck()标记要检查到根组件的路径 -要更新的内容
  2. markForCheck()让变化检测发生在当前或下一个周期 -定时

我的想法或问题:

  1. 为什么我们需要检查到根的整个路径(在async管道中)?为什么不只是当前组件?( detectChanges()) - 这与要更新的内容有关

  2. 为什么只标记(用于当前/下一个周期 - 在markForCheck()使用 ngZone 时)?为什么不立即检测变化?( detectChanges()) 这与时间有关

  3. 如果没有 ngZone 异步触发器/没有异步操作怎么办?那么视图更新不会发生?

  4. 如果我们将async管道改为使用会发生什么detectChanges()


异步管道

  private _updateLatestValue(async: any, value: Object): void {
    if (async === this._obj) {
      this._latestValue = value;
      this._ref.markForCheck();
    }
  }

编辑:

当我在文档中多次阅读时,请不要解释每种方法的作用,从async角度来看,我无法理解。我要知道的重要部分是为什么要更新什么时间

4

2 回答 2

2

对于正确的文档检查ChangeDetectorRef

检测变化

检查此视图及其子视图

如果你的类发生了变化,但视图还没有更新,你需要通知 Angular 来检测这些变化。

标记检查

当视图使用 OnPush (checkOnce) 更改检测策略时,显式将视图标记为已更改,以便可以再次对其进行检查。

仅从文本中您已经可以看到,该策略用于组件检测策略已更改为onPush(例如,如果@Input()已更改)的情况。

更新

直接回答您的问题:

  1. 为什么我们需要检查到根的整个路径(在异步管道中)?为什么不只是当前组件?(detectChanges()) - 这与要更新的内容有关

它不是检查根,而是检查组件的祖先 在此处输入图像描述

  1. 为什么只标记(用于当前/下一个周期 - 在 markForCheck() 中使用 ngZone)?为什么不立即检测变化?(detectChanges()) 这与时间有关

我认为这是一个与性能相关的话题。收集所有需要运行的检查并在下一个周期中执行它们。

  1. 如果没有 ngZone 异步触发器/没有异步操作怎么办?那么视图更新不会发生?

正确,如果 Angular 不会被通知,那么视图中不会发生任何变化

  1. 如果我们将异步管道改为使用 detectChanges() 会发生什么?

我想它也可以工作,但它不会只检查更改,而是直接执行视图的更新。

于 2020-10-19T08:53:29.673 回答
1

正如 Angular 文档所说

detectChanges()是:

检查此视图及其子视图。与 detach 结合使用以实现本地更改检测检查。

markForCheck()是:

当视图使用 OnPush (checkOnce) 更改检测策略时,显式将视图标记为已更改,以便可以再次对其进行检查。

因此detectChanges()立即运行更改检测,但markForCheck()不运行更改检测。

所以看起来async管道用于markForCheck避免性能问题。我的意思是markForcheck()async管道中使用有助于避免运行不必要的更改检测。

更新:

问题一:

如果没有正在进行的当前更改检测并且没有用于未来 CD 的 ngZone 异步触发器怎么办?

不,视图不会更新,但是,它将标记从当前组件到根组件的所有组件,它们的状态为CheckEnabled源代码:

export function markParentViewsForCheck(view: ViewData) {
    let currView: ViewData|null = view;
    while (currView) {
        if (currView.def.flags & ViewFlags.OnPush) {
           currView.state |= ViewState.ChecksEnabled;
        }
    currView = currView.viewContainerParent || currView.parent;
    }
}

问题2:

至于要更新什么,为什么我需要将整个路径标记到根目录?...在第二个解决方案(detectChanges)中不是吗?

请阅读这个很好的答案Angular markForCheck vs detectChanges。总之,最好用markForCheck()方法。

于 2020-10-19T09:05:47.827 回答