This gist is a small summary of debug-angular-performance-better-with-these-tools
In my AppModule
, I first inject ApplicationRef
in the constructor and patch the tick()
function with some logging code:
export class AppModule {
constructor(applicationRef: ApplicationRef) {
if (isDevMode()) {
// First, store the original tick function
const originalTick = applicationRef.tick
applicationRef.tick = function () {
// Save start time
const windowsPerfomance = window.performance
const before = windowsPerfomance.now()
// Run the original tick() function
const returnValue = originalTick.apply(this, arguments)
// Save end time, calculate the delta, then log to console
const after = windowsPerfomance.now()
const runTime = after - before
window.console.log('[Profiler] CHANGE DETECTION TIME', runTime, 'ms')
return returnValue
}
}
}
}
See profiler.ts
Usage:
@ProfileClassToConsole()
@Component({
// ...
})
export class MyComponent {
// ...
}
To enable these tools, you need to add a few line of code in your src/main.ts
.
import { ApplicationRef, isDevMode } from '@angular/core'
import { enableDebugTools } from '@angular/platform-browser'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { AppModule } from './app/app.module'
// ... other bootstrap code
platformBrowserDynamic()
.bootstrapModule(AppModule)
.then(moduleRef => {
if (isDevMode()) {
// Enable console debug tools
const appRef = moduleRef.injector.get(ApplicationRef)
const componentRef = appRef.components[0]
enableDebugTools(componentRef)
}
})
.catch(err => console.error(err))
One of the tool enabled is ng.profiler.timeChangeDetection()
.
This funtion basically run the app's root CD a few time and print out average time required.
In your browser's Dev Console, type ng.profiler.timeChangeDetection()
Angular dev tool provide us with a function that allow us to tap into a component's state and infomation at runtime, as well as altering some of its state (or call its internal methods).
We were on Angular 5 when I worked on these so ng.probe().componentInstance
is what I used.
If you are on version 9 and above with Ivy
compiler, the function has changed to ng.getComponent()
.
In Chrome, if you select something in the inspector, you may notice it says == $0
at the end.
If you use the inspector to select any Angular Component (e.g. tag) and pass it to ng.probe()
(ng.probe($0)
), it will return something interesting
Note, with ng.probe()
, you can actually select any of the component's child node, as long as that node is not an Angular Component itself, and ng.probe()
will find the right Angular Component.
With ng.getComponent()
however, you will need to select the Angular Component's selector tag itself.
To get the most out of ng.probe()
for performance debugging, you can inject ChangeDetectorRef
into your component.
This will allow us to access the component's change detector at runtime.
You can use detach()
and reattach()
to manually turn CD
off and on for a particular component, enabling you to somewhat isolate the effect of a component's change detection cycle on overall app's performance.
For example, if detaching a component's CD
reduce the overall CD
time by 50ms
then you can say that the component or some of its children is costing around 50ms
of time to complete its CD
.