有角。为什么调用markForCheck()结果来查看更新

sim*_*ood 6 angular angular-changedetection

到处都说 markForCheck 只是将当前组件视图和所有父组件(直到根组件)标记为脏组件。因此下次执行 DetectChanges 时它将更新视图。从这一点上我有两个问题。两者都在该组件具有的上下文中changeDetection: ChangeDetectionStrategy.OnPush

1)如果“async pipeline”除了调用markForCheck(源代码)什么都不做,为什么视图会更新?

2)如果我尝试在某个异步进程中调用markForCheck,视图也会更新。

演示:stackblitz

您能帮助我了解这些过程中发生的情况以及视图实际更新的原因吗?我期待有人在 1) 和 2) 之后调用 DetectChanges 方法,但是谁......

sim*_*ood 3

在@David 的帮助下我找到了答案。

首先,RxJs 无论如何都没有用区域包装,但本机异步函数是(as setTimer/Itervalfetchapi 、XHRDOM events)。由于 RxJs 定时器/延迟(...) 运算符使用本机异步函数,这导致它们也在区域上下文中进行处理。

tap这就是当我们处于 Rx操作符时 Callstack 的样子

在此输入图像描述 您可以看到 Rx 部分位于 Angular/Zone 1 之后。

每当执行异步回调时,Angular就会使用区域来调用函数。tick()Tick方法从根组件向下查找标记为检查视图。

我在tick函数中放置了断点,它在我们的回调执行后被调用

在此输入图像描述

async pipe那么当我们在模板上使用第一种情况时会发生什么。

  1. 异步回调由异步管道运算符处理,并调用 markForCheck() 函数
  2. 正如我们所知,markForCheck 将当前视图和父视图标记为 RootComponent 进行检查
  3. 步骤 1 的回调完成后,tick()将调用 。最后将检查视图并更新它

当我们在 RxJs 操作符内部调用时,第二种情况几乎会发生同样的情况markForCheck。我们做同样的事情async pipe,并且因为我们的回调也用区域包装,所以我们在回调完成后执行相同的过程。

如果您不在异步回调中调用markForCheck,而是调用tick函数,则不会进行任何更新。值得一提的是,如果您调用 detectorChanges(),尽管没有调用 markForCheck 函数,更新也会完成。这是stackblitz上的示例 这是由于 ChangeDetectorRef 的 detechChanges 忽略 markForCheck 标志并对 Component 及其所有子组件进行更改检测。这篇文章中有更多详细信息

此方法对当前组件视图运行更改检测,无论其状态如何