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.
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 }}
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.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!
📚 Source code of what we've done