A zone is an execution context that persists across async tasks. You can think of it as thread-local storage for JavaScript VMs. Zones in Zone.js are hierarchical. This means that new zones are created by “forking” an existing zone. When you fork a zone, the new zone inherits the behaviours of its parent but can also have additional behaviours or modifications.

NgZone

In the context of Angular, the framework doesn’t directly use the root zone. Instead, Angular creates its specialized zone by forking the root zone.

This forked zone, known as NgZone or sometimes referred to as the “inner zone,” is augmented with Angular-specific behaviors. It’s within this NgZone that Angular tracks changes and decides when to run its change detection.

NgZone run() and runOutsideOfAngular()

Zone handles most asynchronous APIs such as setTimeout()Promise.then(), and addEventListener(). For the full list, see the Zone Module document. In those asynchronous APIs, we don’t need to trigger change detection manually.

Some third party APIs are not handled by Zone. In those cases, the NgZone service provides a run() method that allows us to run a function inside the Angular zone. This function, and all asynchronous operations in that function, triggers change detection automatically at the correct time.

export class AppComponent implements OnInit {
  constructor(private ngZone: NgZone) {}
  ngOnInit() {
    // New async API is not handled by Zone, so you need to use ngZone.run()
    // to make the asynchronous operation callback in the Angular zone and
    // trigger change detection automatically.
    someNewAsyncAPI(() => {
      this.ngZone.run(() => {
        // update the data of the component
      });
    });
  }
}

By default, all asynchronous operations are inside the Angular zone, which triggers change detection automatically. Another common case is when you don’t want to trigger change detection. In that situation, you can use another NgZone method: runOutsideAngular().

export class AppComponent implements OnInit {
  constructor(private ngZone: NgZone) {}
  ngOnInit() {
    // You know no data will be updated,
    // so you don't want to trigger change detection in this
    // specified operation. Instead, call ngZone.runOutsideAngular()
    this.ngZone.runOutsideAngular(() => {
      setTimeout(() => {
        // update component data
        // but don't trigger change detection.
      });
    });
  }
}

Setting up Zone.js

To make Zone.js available in Angular, we need to import the zone.js package. If we are using the Angular CLI, this step is done automatically, and we can see the following line in the src/polyfills.ts:

/***************************************************************************************************
 * Zone JS is required by default for Angular itself.
 */
import 'zone.js';  // Included with Angular CLI.

Before importing the zone.js package, we can set the following configurations:

  • Disabling some asynchronous API monkey patching for better performance. For example, disabling the requestAnimationFrame() monkey patch, so the callback of requestAnimationFrame() does not trigger change detection. This is useful if, in our application, the callback of the requestAnimationFrame() does not update any data.
  • Specify that certain DOM events do not run inside the Angular zone. For example, to prevent a mousemove or scroll event to trigger change detection

Several other settings can be changed. To make these changes, we need to create a zone-flags.ts file, such as the following.

// disable patching requestAnimationFrame
(window as any).__Zone_disable_requestAnimationFrame = true;

// disable patching specified eventNames
(window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove'];

Next, import zone-flags before we import zone.js in the polyfills.ts:

/***************************************************************************************************
 * Zone JS is required by default for Angular.
 */
import `./zone-flags`;
import 'zone.js';  // Included with Angular CLI.

For more information about what we can configure, see the Zone.js documentation.

Summary

runOutsideAngular can be used to run code outside of Angular so it doesn’t trigger change detection unnecessarily. This can be used for example to run multiple HTTP requests to get all the data before rendering it.

To run the code again in Angular, NgZone’s run method can be used.

import {
 Component,
 OnInit,
 NgZone
}
 from '@angular/core';

@Component({
    ...
})  

export class Mycomponent implements OnInit {
 constructor(private zone: NgZone) {}
    ngOnInit() {

     this.zone.runOutsideAngular(() => {

             //write here any bussiness Logic, you want to compute outside Angular
            ).subscribe(() => {
              // do nothing on success or compute some other logis
            }, (e: Error) => {
              this.zone.run(() => {

                //Here you can now run your code in Angular
                this.connectionSubject.next(ConnectionState.DISCONNECTING);
              });
            });
          });
  }

}

NoopZone

Zone helps Angular know when to trigger change detection and let the developers focus on the application development. By default, Zone is loaded and works without further configuration. We don’t necessarily have to use Zone to make Angular work. Instead, we can opt to trigger change detection on our own.

To remove Zone.js, make the following changes.

  1. Remove the zone.js import from polyfills.ts:
/***************************************************************************************************
 * Zone JS is required by default for Angular itself.
 */
// import 'zone.js';  // Included with Angular CLI.

2. Bootstrap Angular with the noop zone in src/main.ts:

platformBrowserDynamic().bootstrapModule(AppModule, { ngZone: 'noop' })
.catch(err => console.error(err));

PS: Disabling Zone requires you to trigger all change detection at the correct timing yourself, which requires comprehensive knowledge of change detection.

By Shabazz

Software Engineer, MCSD, Web developer & Angular specialist

Leave a Reply

Your email address will not be published. Required fields are marked *