@rx-angular/cdk/zone-less
A set of wrappers for Browser native as well as RxJS functions to avoid unnecessary change detection and zone interference in Angular.
@rx-angular/cdk/zone-less
is designed to help developers improve performance by not using zone.js patched API's.
Besides a well documented and typed API it provides a way to use patched API's in a way that is independent of ngZone runOutsideZone
usage.
Key features
- ✅ unpatched Browser API's
- ✅ no need for
runOutsideAngular
Install
npm install --save @rx-angular/cdk
# or
yarn add @rx-angular/cdk
Documentation
Motivation
By default, Angular or better say zone.js patches most of the asynchronous APIs of the Browser. This adds additional overhead on those APIs and even more important, this leads to unnecessary renderings of the Angular component tree, also known as overrendering.
Until now developers were only able to either disable zone.js completely or wrap another logic around the patched APIs to avoid change detection calls. This of course requires injecting another service and also makes your code more cluttery and slow.
The zone-less package helps out here. It provides a general method to access the unpatched version of an API and also ships a set of commonly used APIs of the Browser as well as RxJS. All those APIs are entirely independent of zone.js and NgZone (normally used to run things outside Angular).
The benefits
- ✅ Finegrained ways to unpatch APIs
- ✅ Fastest option possible to run code outside of Angular's zone mechanism
- ✅ Drop-in replacement for native APIs
- ✅ Drop-in replacement for RxJS functions
- ✅ No need for
runOutsideAngular
andNgZone
injection
RxAngular CDK/Zone-less
The way how zone.js works is, it patches all relevant async APIs of the Browser. This happens early on as zone.js is treated as polyfill.
All original logic of the patched API's is stored under a symbol in window
. You can check that by logging for example the following value: console.log(window.__zone_symbol__setTimeout)
.
This will print the original unpatched API to the Browsers console.
Internally the symbols and in turn the unpatched APIs is what the zone-less package is using.
The essential method used to get hold of the unpatched APIs is called getZoneUnPatchedApi
. It takes a target i.e. window
and a name of the method we want to retrieve the unpatched version of.
Setup
The zone-less APIs can be used directly from the cdk
package.
To do so, install the cdk
package and, if needed, the packages depending on it:
- Install
@rx-angular/cdk
npm i @rx-angular/cdk
// or
yarn add @rx-angular/cdk
Usage
The utils folder contains the most essential functions used to unpatch APIs.
Normally if developers want to avoid change detection through zone they have to inject NgZone
and run the code that should not trigger change detection in the runOutsideAngular
method.
export class AnyComponent {
constructor(private ngZone: NgZone) {
this.ngZone.runOutsideAngular(() => {
// code here
});
}
}
This introduces some lines of code and also takes time to retrieve the service from dependency injection and execute additional code.
utils
- getZoneUnPatchedApi
The getZoneUnPatchedApi
function is used in all other functions of the zone-less package to access the Browsers unpatched APIs.
@Component({
// ...
})
export class AppComponent {
doStuff() {
// unpatched method of the window object
getZoneUnPatchedApi('setTimeout')(() => console.log('tada!'), 300);
}
doOtherStuff() {
// unpatched method of an HTML element
getZoneUnPatchedApi(elem, 'addEventListener')('click', () =>
console.log('tada!')
);
}
}
browser
- requestAnimationFrame
- cancelAnimationFrame,
- setInterval,
- clearInterval,
- setTimeout,
- clearTimeout
To reduce lines of code we ship all common browser scheduling APIs as unpatched version directly.
import { setTimeout } from '@rx-angular/cdk/zone-less/browser';
@Component({
// ...
})
export class AppComponent {
doStuff() {
// unpatched method of the window object
setTimeout(() => console.log('tada!'), 300);
}
}
Available approaches
ngZone#runOutsideZone
zone-configuration
ngZone#runOutsideAngular
It is possible to inject an instance of NgZone into components and services etc to tell Angular to run a specific piece of code outside of Angular.
@Component({
// ...
})
export class AppComponent {
constructor(private ngZone: NgZone) {}
doStuff() {
this.ngZone.runOutsideAngular(() => {
setTimeout(() => {
console.log('tada!');
}, 300);
});
}
}
The downside here is we need to inject NgZone
and rely on dependency injection which is not only more code but also slow.
Zone Configuration
Zone configuration is a less granular way to disable zone. It helps to configure zone in a way where it doesn't patch specific APIs at all.
You can read in detail about it in the docs of @rx-angular/cdk/zone-configuration
.