首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么角异步管道使用cdr.markForCheck()而不是cdr.detectChanges()?

为什么角异步管道使用cdr.markForCheck()而不是cdr.detectChanges()?
EN

Stack Overflow用户
提问于 2020-10-19 08:07:14
回答 2查看 1.2K关注 0票数 5

我有一个一般性的角度问题:

为什么角async管使用cdr.markForCheck()而不是cdr.detectChanges()

我所看到的这两种“风格”主要有两个不同之处:

  1. markForCheck()标记要检查到根组件的路径-要更新的内容
  2. markForCheck()允许在当前或下一个周期中进行更改检测-定时

我的想法或问题:

  1. 为什么我们需要检查根的整个路径(在async管道中)?为什么不只是当前组件?(detectChanges()) -这涉及到更新的内容
  2. 为什么只标记(当前/下一个周期-在markForCheck()中使用ngZone)?为什么不立即检测更改?(detectChanges())这与定时有关
  3. 如果没有ngZone异步触发器/没有异步操作怎么办?那么视图更新就不会发生了?
  4. 如果我们将async管道改为使用detectChanges(),会发生什么情况?

异步管道

代码语言:javascript
复制
  private _updateLatestValue(async: any, value: Object): void {
    if (async === this._obj) {
      this._latestValue = value;
      this._ref.markForCheck();
    }
  }

编辑:

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-10-19 08:53:29

为了获得适当的文档,请检查ChangeDetectorRef

detectChanges

检查此视图及其子视图。

如果类已更改,但视图尚未更新,则需要通知角以检测这些更改。

markForCheck

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

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

更新

直接回答你的问题:

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

它不是检查根,而是检查组件的祖先。

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

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

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

正确,如果不通知角度,那么视图中什么都不会改变。

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

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

票数 2
EN

Stack Overflow用户

发布于 2020-10-19 09:05:47

就像医生说的

detectChanges()是:

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

markForCheck()是:

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

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

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

更新:

问题1:

如果没有正在进行的当前更改检测,也没有针对未来CD的ngZone异步触发器,怎么办?

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

代码语言:javascript
复制
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:

至于要更新什么,为什么我需要将整个路径标记为根呢?第二个解决方案中的...and (detectChanges)不需要?

请读这个不错的答案,角markForCheck对detectChanges。总之,最好使用markForCheck()方法。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64423407

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档