NG Zone Angular - Improve Performance by Running Code Outside Angular
NG Zone Angular - Improve Performance by Running Code Outside Angular

In this post you will learn what is NgZone inside Angular.

NgZone gives us a possibility to run something outside Angular and inside. Here you for sure think that it doesn't make any sense to run anything outside Angular if we are using Angular framework. It totally does as there are some cases when you want to do that.

First of all when we are talking about third party libraries which are not build with Angular.

Query builder

Which actually means that you have some complex library which was created just in plain Javascript. Angular doesn't know anything about this library and in order to bind it to Angular you must execute some commands of this library inside Angular and synchronize the results with the state inside Angular so you can apply it to your project.

Another use case if you want to optimize your performance and you want to avoid Angular digest cycle. When you have some task which is not performant for Angular it doesn't make any sense to do it inside Angular.

Angular reacts to your every single change and will rerender your components tree every single time.

This is not efficient. This is why sometimes we want to move this code outside of the Angular. Here on a simple example I want to show you how we can do that. Here I want to do an example of drag n drop. But please don't try to use this code directly on production as it is just for understanding the concepts.

Also don't think that you need to move all your code outside of Angular to make it faster. If you don't have problems then don't optimize it.

Real example

Here I'm inside app.component and I want to create an element with mouse down and mouse up events.

<div (mousedown)="mouseDown($event)" (mouseup)="mouseUp($event)" #element>
  Element
</div>

Now we must define these 2 functions and a reference to our element.

export class AppComponent {
  @ViewChild('element', { static: true }) element: any;

  mouseDown(event: any) {
  }

  mouseUp(event: any) {
  }
}

As you can see I wrote any everywhere. This is just to simplify code and to focus on NgZone.

export class AppComponent {
  @ViewChild('element', { static: true }) element: any;

  constructor(private zone: NgZone) {}

  mouseDown(event: any) {
    this.zone.runOutsideAngular(() => {
      window.document.addEventListener('mousemove', this.mouseMove.bind(this));
    });
  }

  ...
}

Here we injected NgZone to our component and called this.zone.runOutsideAngular inside mouseDown. We provide inside a function which code that we want to execute outside of the Angular. Now we need to add mouseMove function. Keep in mind that we we used bind to provide correct this inside a function.

export class AppComponent {
  ...
  mouseMove(event: any) {
    this.element.nativeElement.setAttribute('x', event.clientX);
    this.element.nativeElement.setAttribute('y', event.clientY);
  }
  ...
}

Here is our mouseMove function which just writes x and y as attributes inside a DOM element without using Angular at all. These are our mouse coordinates.

export class AppComponent {
  position: any;

  ...

  mouseUp(event: any) {
    this.zone.run(() => {
      this.position = {
        x: this.element.nativeElement.getAttribute('x'),
        y: this.element.nativeElement.getAttribute('y'),
      };
    });

    window.document.removeEventListener('mousemove', this.mouseMove);
  }
}

And here we defined position which is either undefined or object with x and y. Inside mouseUp we call this.zone.run which executes code inside Angular again. Inside we assign the values from the DOM to our position property and call removeEventListener to unsubscribe from the mousemove.

The last thing that we want to do is to render position in our markup.

{{ position | json }}

Result

Here I made mouse down on the element and start to move the cursor. You can see that with every move we update attributes in the DOM element but it happens outside of the Angular. Only when I make mouseup on our element it renders position in Angular markup.

And actually if you want to learn Angular with NgRx from empty folder to a fully functional production application make sure to check my Angular and NgRx - Building Real Project From Scratch course.

📚 Source code of what we've done