2

I am wondering if all asynchronous events and callbacks can be traced back to a specific source component by wrapping all component logic (including logic of non-component directives inside component) in a zone, then only that source component needs to be checked for changes along with any child components with changed inputs from the source component, assuming all changes are following the uni-directional flow.

Is this understanding sound?

Is this change detection strategy available in Angular2?

Why is Angular2 detecting changes on all the components after any asynchronous (XHR) event?

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
geeko
  • 2,649
  • 4
  • 32
  • 59
  • I think you're looking for `ChangeDetectionStrategy: OnPush` ? Also here's a very detailed article on changedetection in 2 if you're interested (http://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html) – Mark Pieszak - Trilon.io Jun 28 '16 at 15:23
  • @MarkPieszak Thank you for your comment. I have read a lot about change detection in AJS 2. I am talking about default strategy with no immutables or observables. – geeko Jun 28 '16 at 15:26
  • Oh the default strategy, yes, well they tried to keep it similar to Angular1 where you want to check everything, since an async event could change so many things on the page (components / routes / data / what have you). Typically Async is always updating *something*, so unless you specify OnPush or something, they just assume everything should be checked. Although the change detection is extremely fast so it isn't an issue like it was in the first Angular! – Mark Pieszak - Trilon.io Jun 28 '16 at 15:29

2 Answers2

1

One whole Angular application runs in a single zone. Angular uses the zone to patch async APIs and uses notifications from these patched APIs to run change detection every time some async event happened.

The uni-directional flow is for [prop]="value" bindings that works only from parent to child.

Angular runs change detection from root to leafs.

If ChangeDetectionStrategy.OnPush is configured for a component, change detection skips these components (and their descendants) until some binding (inputs) have changed.

There are other strategies to optimize CD.

  • For example observables and promises, that actively notify about changes and don't need change detection.

  • Immutable objects which are guaranteed to not change their propery values.

Update

Angular doesn't know what values an event handler has changed. Properties of a component, of a global service, of object references that were passed around, .... It just assumes that when an event handler was called that probably something has changed and then runs a complete change detection cycle to propagate all bindings from parent to child.

Child do parent bindings are events anyway and therefore aren't updated during change detection.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Nicely said Gunter! One thing to note as well, is that the three things patched with Zones are 1) `Timers` (timeouts, etc) 2) `XHR` (ajax) 3) `Events` (clicks etc). Any of these 3 things can cause change detection. (For those who are curious) – Mark Pieszak - Trilon.io Jun 28 '16 at 15:47
  • Thank you. I am actually asking why does not AngularJS wrap each component inside a separate zone so that asynchronous events can be traced back to the source component and hence can optimize the default change detection strategy as I have described in my question? – geeko Jun 28 '16 at 15:47
1

... by wrapping all component logic (including logic of non-component directives inside component) in a zone, then only that source component needs to be checked for changes along with any child components with changed inputs from the source component, assuming all changes are following the uni-directional flow. Is this understanding sound?

When an template-bound event fires – e.g., (click)="doSomething()" – the doSomething() method is free to alter any component or application data. Template statements, such as our doSomething() event handler, are not bound by the unidirectional flow rule, as per the Angular docs:

Responding to events is the other side of Angular's "unidirectional data flow". We're free to change anything, anywhere, during this turn of the event loop.

This is why, by default, Angular's change detection has to check every template binding in every component after an event fires. (Well, after an event within the Angular zone fires.) Angular doesn't know what might have changed... it has to discover what has changed.

The unidirectional flow rule applies to template expressions such as {{some expression}} or [childInputProperty]="parent expression" or if you implement an input property setter method: @Input() set childInputProperty(variableName:type) { ... }.

Is this change detection strategy available in Angular2?

No, because it would severely limit what an event handler could do. Dirty-checking every template binding may not be the most efficient way to detect changes, but it makes it much easier for us to write our event handlers (i.e., to write our applications).

Why is Angular2 detecting changes on all the components after any asynchronous (XHR) event?

Angular doesn't want to limit what we can do in our event handlers. An event handler bound in ComponentA's template can change data that is local to ComponentA, but it can also change data that is in a service (and hence it can change data that is visible to other components), and it can change data in other components, e.g., by calling public APIs/methods on other components.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492