Angular。为什么调用markForCheck()结果查看更新
Angular. Why calling markForCheck() results to view update
到处都说 markForCheck 只是将当前组件视图和所有父组件(直到根组件)标记为脏。因此,下次执行 DetectChanges 时,它将更新视图。
从这一点来看,我有两个问题。在组件具有 changeDetection: ChangeDetectionStrategy.OnPush
的上下文中
1) 如果'async pipe'除了调用markForCheck(source code)什么都不做,为什么要更新视图?
2) 如果我尝试在某个异步进程中调用 markForCheck,视图也会更新。
演示:stackblitz
你能帮我理解在这些过程中发生了什么以及为什么视图实际更新了吗?我期待有人在 1) 和 2) 之后调用 DetectChanges 方法,但是谁...
看到onpush时,输入的任何变化都会使组件变脏,然后只重新渲染。但是如果你想在没有这些事件的情况下使它变脏,你可以调用 markDirty 方法来让 changeDetection 发生。请在下面找到 link 到官方声明:-
在@David 的帮助下我找到了答案。
首先,RxJs 无论如何都没有用区域包装,但是原生异步函数是(如 setTimer/Iterval
、fetch
api、XHR
、DOM events
).由于 RxJs timer/delay(...) 运算符使用本机异步函数,这导致它们也在区域上下文中处理。
这就是我们在 Rx tap
运算符中时调用堆栈的样子
你可以看到 Rx 部分在 Angular/Zone 之后。
每当执行异步回调时,Angular 轮到 使用区域调用 tick()
函数。 Tick
方法从根组件向下并查找标记为检查视图。
我在tick函数中下了断点,它在我们的回调执行后被调用
那么当我们在模板上使用 async pipe
时,第一种情况会发生什么。
- 异步回调由异步管道操作符处理并调用 markForCheck() 函数
- 我们知道 markForCheck 将当前视图和父视图标记为要检查的 RootComponent
- 步骤 1 的回调完成后,调用
tick()
。最后将检查视图并更新它
几乎相同的情况发生在第二种情况下,当我们在 RxJs 运算符中调用 markForCheck
时。我们做与 async pipe
相同的事情,并且因为我们的回调也用区域包装,所以我们在回调完成后执行相同的过程。
如果您不在异步回调中调用 markForCheck,而是调用 tick 函数,则不会进行任何更新。
值得一提的是,如果您调用 detectChanges(),尽管没有调用 markForCheck 函数,更新也会完成。
这是 stackblitz 上的示例
这是由于 ChangeDetectorRef 中的 detechChanges 忽略了 markForCheck 标志并对 Component 及其所有子项进行更改检测。
article
中有更多详细信息
This method runs change detection for the current component view regardless of its state
到处都说 markForCheck 只是将当前组件视图和所有父组件(直到根组件)标记为脏。因此,下次执行 DetectChanges 时,它将更新视图。
从这一点来看,我有两个问题。在组件具有 changeDetection: ChangeDetectionStrategy.OnPush
1) 如果'async pipe'除了调用markForCheck(source code)什么都不做,为什么要更新视图?
2) 如果我尝试在某个异步进程中调用 markForCheck,视图也会更新。
演示:stackblitz
你能帮我理解在这些过程中发生了什么以及为什么视图实际更新了吗?我期待有人在 1) 和 2) 之后调用 DetectChanges 方法,但是谁...
看到onpush时,输入的任何变化都会使组件变脏,然后只重新渲染。但是如果你想在没有这些事件的情况下使它变脏,你可以调用 markDirty 方法来让 changeDetection 发生。请在下面找到 link 到官方声明:-
在@David 的帮助下我找到了答案。
首先,RxJs 无论如何都没有用区域包装,但是原生异步函数是(如 setTimer/Iterval
、fetch
api、XHR
、DOM events
).由于 RxJs timer/delay(...) 运算符使用本机异步函数,这导致它们也在区域上下文中处理。
这就是我们在 Rx tap
运算符中时调用堆栈的样子
Angular 轮到 使用区域调用 tick()
函数。 Tick
方法从根组件向下并查找标记为检查视图。
我在tick函数中下了断点,它在我们的回调执行后被调用
那么当我们在模板上使用 async pipe
时,第一种情况会发生什么。
- 异步回调由异步管道操作符处理并调用 markForCheck() 函数
- 我们知道 markForCheck 将当前视图和父视图标记为要检查的 RootComponent
- 步骤 1 的回调完成后,调用
tick()
。最后将检查视图并更新它
几乎相同的情况发生在第二种情况下,当我们在 RxJs 运算符中调用 markForCheck
时。我们做与 async pipe
相同的事情,并且因为我们的回调也用区域包装,所以我们在回调完成后执行相同的过程。
如果您不在异步回调中调用 markForCheck,而是调用 tick 函数,则不会进行任何更新。 值得一提的是,如果您调用 detectChanges(),尽管没有调用 markForCheck 函数,更新也会完成。 这是 stackblitz 上的示例 这是由于 ChangeDetectorRef 中的 detechChanges 忽略了 markForCheck 标志并对 Component 及其所有子项进行更改检测。 article
中有更多详细信息This method runs change detection for the current component view regardless of its state