Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find which async action triggers ngZone (that lead to Change Detection)?

Any changes in the stack trace of updates always lead back to globalZoneAwareCallback. How do you find out what triggered the change?

In terms of debugging it's good to have a clear picture.

like image 347
user2167582 Avatar asked Nov 19 '19 22:11

user2167582


People also ask

Which service is used by developers to start change detection resulted by async operations automatically?

In those cases, the NgZone service provides a run() method that allows you to execute a function inside the angular zone. This function, and all asynchronous operations in that function, trigger change detection automatically at the correct time.

What is the use of NgZone?

A zone is an execution context that persists across async tasks. You can think of it as thread-local storage for JavaScript VMs. This guide describes how to use Angular's NgZone to automatically detect changes in the component to update HTML.

What is runOutsideAngular?

Running functions via runOutsideAngular allows you to escape Angular's zone and do work that doesn't trigger Angular change-detection or is subject to Angular's error handling. Any future tasks or microtasks scheduled from within this function will continue executing from outside of the Angular zone.

What is Zonejs?

Zone. js is a library created by Brian Ford in 2010 and is inspired by Dart. It provides a concept called Zone , which is an execution context that persists across async tasks. A Zone can: Provide execution context that persist across async tasks.


1 Answers

globalZoneAwareCallback is a function declared in zonejs for handling all event callbacks with capture=false. (btw, for capture=true there is globalZoneAwareCaptureCallback)

It means that any event listener will first go through this method. That listener can be added on the page by Angular, by you or by any 3rd party library.

There are many ways of how we can listen to browser events in Angular:

  • subscribe to browser event <element (event)="callback()">

  • @HostListener decorator @HostListener('event') callback() {}

  • Renderer2.listen method

  • rxjs fromEvent

  • assign element property element.on<event> = callback

  • addEventListener method element.addEventListener(event, callback)(this method is used internally in many other ways above)

Once you're within globalZoneAwareCallback you have access to all Zone tasks that should be triggered.

Let's imagine we listen to click event on document.body:

document.body.addEventListener('click', () => {
   // some code
});

Let's open Chrome dev tools to have a clear picture:

enter image description here

What we've just discovered:

  • each Zone task contain source so this is what triggers the change

  • target property shows which object triggers the change

  • callback property can lead us to the handler of the change

Let's consider another example and add click event using Angular way:

<h2 class="title" (click)="test()">Hello {{name}}</h2>

Once we click on that h2 element we should observe the following:

enter image description here

You might be surprised that now callback property didn't bring us to the test callback right away but rather we showed some wrapper from @angular/platform-browser package. And other cases also may differ but ZoneTask.source property is usually all you need in those cases because it shows you the root cause of the change.

like image 88
yurzui Avatar answered Sep 27 '22 19:09

yurzui