Angular 2 变更检测 - 如何解决组件之间的循环依赖?

Angular 2 change detection - How are circular dependecies between components resolved?

我读到 Angular2 变更检测是单向的,从组件树的顶部到底部,并且在一次通过后就稳定了,这意味着没有多个变化检测周期。鉴于这些假设,如果我们有一个具有相互依赖的属性的父组件和子组件,会发生什么情况?示例:

  1. 基于用户事件,父组件更新子组件属性
  2. 此更新会在子组件中触发一个事件,该事件会更新父组件
  3. 上的 属性
  4. 父 属性 更新触发另一个更新子组件的事件
  5. ...

据我了解,Angular 1 中的类似情况已通过对这些相互依赖的属性触发的循环数设置限制来解决,这会导致框架抛出错误。

Angular2 是如何解决的?上例中的哪一点真正触发了变化检测?

在 devMode 中,变化检测会连续进行两次。如果第二轮识别出它抛出的变化。因此变化检测本身不能引起模型的变化。

Angular2 变化检测只更新从父到子。因为变化检测本身不能引起变化,所以当所有的变化都传播到叶节点上时,变化检测就完成了。

当事件或任何其他异步调用发生时,它会被完全处理,并且还会导致从子级到父级的更改(输出)。完成后,更改检测会从根传播到叶。

这样 Angular2 变化检测避免了循环。

I've read that Angular 2 change detection... gets stable after a single pass

Angular 2 没有 "get stable"。对于 Angular 2 个应用程序,我们负责编写我们的应用程序,使其在单次通过后始终保持稳定。

默认情况下(例如,您没有使用 OnPush change detection strategy on any components, nor did you detach() 任何组件),更改检测的工作方式如下:

  • A Zone.js monkey-patched 异步事件触发——例如,一个 (click) 事件,一个 XHR 响应,一个 setTimeout() 定时器。与该事件关联的回调 运行s,它可以更改我们应用程序中的任何视图或应用程序数据。然后,由于猴子补丁,Angular 更改检测 运行s。换句话说,默认情况下(例如,你不是 ),只有 monkey-patched 异步事件触发变更检测。
  • 从根组件开始,向下遍历组件树(深度优先遍历),检查每个数据绑定是否有变化。如果发现更改,则更改为 "propagated"。根据模板绑定类型,传播可能
    • 将更改后的值传播到 DOM。例如,当使用 {{}} 绑定时,新值将传播到适当 DOM 元素的 textContent 属性。
    • 将更改后的值传播到子组件。例如,当使用输入 属性 绑定 ([childInputProperty]="parentProperty") 时,新值将传播到子输入 属性.
  • 如果您处于开发模式,将再次对所有组件进行脏检查,但不会发生传播。这第二个脏检查帮助我们发现我们代码的问题,例如,如果我们违反了 idempotent rule,这是一种奇特的说法,说明我们的绑定(它的模板表达式)有副作用。换句话说,额外的开发模式检查让我们知道我们的代码在单次通过后是否不稳定。

Angular 中不允许出现副作用 2. 关于您的问题,子组件不得因输入 属性 传播而修改父组件 属性。因此,您可以说 Angular 2 "resolves" 您询问的情况不允许。

这并不像听起来那么糟糕。我知道输入 属性 传播可以更改父 属性 的唯一方法是子组件是否为输入 属性 实现 setter 方法,该方法修改另一个属性 父项显示在其模板中。 (这是执行此操作的 old plunker -- 请参阅 @Input set backdoor() 方法。)通常您不会这样做。如果您确实需要这样做,那么 Günter 的评论是正确的:在 setTimeout() 内进行更改,因此它将成为下一个更改检测周期的一部分。

我想再次强调:事件处理程序 运行 在更改检测之前,因此他们可以自由更改我们应用程序中的任何数据 -- local/component 视图数据,应用程序数据,等等。因此在事件处理程序中,子组件可以自由更改父数据。例如,假设父项和子项都引用了同一个数组。当事件处理程序 运行s 时,父 and/or 子组件可以修改该数组。

因此,如果您对事件处理程序进行更改,没问题。只有当你的 setter 做了一些奇怪的事情时才会有问题。

的确,变化检测是单次执行的,但单个事件后可以有多个循环。

文章 Does Angular applications become stable after a single change detection cycle? 通过说明性示例解释了这一点。