简体   繁体   English

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

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

I've read that Angular 2 change detection is uni-directional, heading from the top to the bottom of the component tree, and that it gets stable after a single pass, meaning that there are no multiple cycles of change detection. 我已经读过Angular 2变化检测是单向的,从组件树的顶部到底部,并且在单次传递后它变得稳定,这意味着没有多个变化检测周期。 Given those assumptions, what will happen in a situation where we have a parent and a child component which have properties that are interdependent? 鉴于这些假设,在我们有父和子组件具有相互依赖属性的情况下会发生什么? Example: 例:

  1. Based on an user event, parent component updates a child component property 基于用户事件,父组件更新子组件属性
  2. This update fires an event in the child component that updates a property on the parent 此更新将触发子组件中更新父项属性的事件
  3. Parent property update fires another event that updates the child component 父属性更新将触发另一个更新子组件的事件
  4. ... ...

From my understanding, similar situation in Angular 1 was resolved by setting a limit on the number of cycles triggered by these interdependent properties, which would cause the framework to throw an error. 根据我的理解,Angular 1中的类似情况通过设置对这些相互依赖的属性触发的循环次数的限制来解决,这将导致框架抛出错误。

How is it resolved with Angular 2? Angular 2如何解决? At which point in the above example is the change detection actually triggered? 在上面的例子中,在哪一点上实际触发了变化检测?

I've read that Angular 2 change detection... gets stable after a single pass 我已经读过Angular 2变化检测......一次通过后变得稳定

Angular 2 doesn't "get stable". Angular 2没有“稳定”。 With Angular 2 apps, we are responsible for writing our app in such a way that it is always stable after a single pass. 使用Angular 2应用程序,我们负责编写应用程序,使其在单次传递后始终保持稳定。

By default (eg, you are not using the OnPush change detection strategy on any components, nor did you detach() any components), change detection works as follows: 默认情况下(例如,您没有在任何组件上使用OnPush更改检测策略,也没有分离()任何组件),更改检测的工作方式如下:

  • A Zone.js monkey-patched asynchronous event fires – eg, a (click) event, an XHR response, a setTimeout() timer. Zone.js猴子修补的异步事件触发 - 例如, (click)事件,XHR响应, setTimeout()计时器。 The callback associated with that event runs, which can change any view or application data in our app. 与该事件关联的回调运行,这可以更改我们的应用程序中的任何视图或应用程序数据。 Then, because of the monkey-patch, Angular change detection runs. 然后,由于猴子补丁,角度变化检测运行。 In other words, by default (eg, you are not manually triggering change detection ), only a monkey-patched asynchronous event triggers change detection. 换句话说,默认情况下(例如,您不是手动触发更改检测 ),只有猴子修补的异步事件才会触发更改检测。
  • Starting from the root component, and traversing down through the component tree (depth-first traversal), each data binding is checked for change. 从根组件开始,遍历组件树(深度优先遍历),检查每个数据绑定的变化。 If a change is found the change is "propagated". 如果发现更改,则“传播”更改。 Depending on the template binding type, propagation may 根据模板绑定类型,传播可以
    • propagate the changed value to the DOM. 将更改的值传播到DOM。 Eg, when {{}} binding is used, the new value is propagated to the textContent property of the appropriate DOM element. 例如,当使用{{}}绑定时,新值将传播到相应DOM元素的textContent属性。
    • propagate the changed value to a child component. 将更改的值传播到子组件。 Eg, when using input property binding ( [childInputProperty]="parentProperty" ), the new value is propagated to the child input property. 例如,当使用输入属性绑定( [childInputProperty]="parentProperty" )时,新值将传播到子输入属性。
  • If you are in dev mode, all of the components are dirty checked again, but no propagation occurs. 如果处于开发模式,则会再次检查所有组件,但不会传播 This second dirty check helps us find problems with our code, eg, if we violated the idempotent rule , which is fancy way of saying that one of our bindings (its template expression) has side effects. 这第二次脏检查有助于我们发现代码存在问题,例如,如果我们违反了幂等规则 ,这是一种奇特的说法,即我们的一个绑定(其模板表达式)具有副作用。 In other words, the extra dev mode checks let us know if if our code is not stable after a single pass. 换句话说,额外的开发模式检查让我们知道我们的代码在单次传递后是否不稳定。

Side effects are not allowed in Angular 2. In reference to your question, a child component therefore must not modify a parent property as a result of input property propagation. Angular 2中不允许出现副作用。在引用您的问题时,子组件因此不能因输入属性传播而修改父属性。 So, you could say that Angular 2 "resolves" the situation you asked about by not allowing it. 所以,你可以说Angular 2通过不允许它来解决你所问的情况。

This is not as bad as it might sound. 这并不像听起来那么糟糕。 The only way I'm aware of that an input property propagation can change a parent property is if the child component implements a setter method for the input property which modifies another property that the parent displays in its template. 我知道输入属性传播可以更改父属性的唯一方法是,子组件为input属性实现setter方法,该方法修改父对象在其模板中显示的另一个属性。 (Here's an old plunker that does this -- see the @Input set backdoor() method.) Normally you wouldn't do this. (这是一个执行此操作的旧插件 - 请参阅@Input set backdoor()方法。)通常,您不会这样做。 If you do need to do this, then Günter's comment is spot on: do the change inside a setTimeout() , hence it will be part of the next change detection cycle. 如果你确实需要这样做,那么Günter的注释就点了:在setTimeout()进行更改,因此它将成为下一个更改检测周期的一部分。

I want to reemphasize: event handlers run before change detection, so they are free to change any data in our app -- local/component view data, application data, whatever. 我想再强调一下: 事件处理程序在更改检测之前运行,因此他们可以自由更改我们应用程序中的任何数据 - 本地/组件视图数据,应用程序数据等等。 So in an event handler, a child component is free to change parent data. 因此,在事件处理程序中,子组件可以自由更改父数据。 Eg, suppose both parent and child have a reference to the same array. 例如,假设父和子都具有对同一数组的引用。 When an event handler runs, the parent and/or child component can modify that array. 当事件处理程序运行时,父组件和/或子组件可以修改该数组。

So if you make changes in event handlers, no problem. 因此,如果您在事件处理程序中进行更改,则没有问题。 There is only a problem if your setter does something odd. 如果你的二传手做了奇怪的事,那就只有一个问题。

In devMode change detection does twice successive turns. 在devMode中,变化检测连续两次转动。 If the 2nd turn recognizes changes it throws. 如果第二个转弯识别出它发生的变化。 Therefore change detection itself must not cause a change of the model. 因此,更改检测本身不得导致模型的更改。

Angular2 change detection only updates from parent to child. Angular2更改检测仅从父级更新为子级。 Because change detection itself must not cause changes, change detection is completed when all changes are propagated onto the leaf nodes. 由于更改检测本身不得导致更改,因此当所有更改都传播到叶节点上时,将完成更改检测。

When an event or any other async call happens, it is fully processed and can also cause changes from child to parents (outputs). 当事件或任何其他异步调用发生时,它将被完全处理,并且还可能导致从子节点到父节点(输出)的更改。 When this is completed, change detection once propagates from root to leaves. 完成此操作后,更改检测一旦从根传播到叶子。

This way Angular2 change detection avoids cycles. 这样,Angular2变化检测避免了循环。

It's true that the change detection is executed in a single pass, but there can be multiple cycles following a single event. 确实,改变检测是在一次通过中执行的,但在单个事件之后可能存在多个周期。

The article Does Angular applications become stable after a single change detection cycle? 文章Angular应用程序在单个更改检测周期后是否变得稳定? explains this point with illustrative examples. 用说明性的例子解释了这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM