mgechev 520ff69854 perf(core): add private hooks around user code executed by the runtime (#41255)
Introduces an **internal**, **experimental** `profiler` function, which
the runtime invokes around user code, including before and after:
- Running the template function of a component
- Executing a lifecycle hook
- Evaluating an output handler

The `profiler` function invokes a callback set with the global
`ng.ɵsetProfiler`. This API is **private** and **experimental** and
could be removed or changed at any time.

This implementation is cheap and available in production. It's cheap
because the `profiler` function is simple, which allows the JiT compiler
to inline it in the callsites. It also doesn't add up much to the
production bundle.

To listen for profiler events:

```ts
ng.ɵsetProfiler((event, ...args) => {
  // monitor user code execution
});
```

PR Close #41255
2021-04-02 10:34:23 -07:00

102 lines
3.0 KiB
TypeScript

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* Profiler events is an enum used by the profiler to distinguish between different calls of user
* code invoked throughout the application lifecycle.
*/
export const enum ProfilerEvent {
/**
* Corresponds to the point in time before the runtime has called the template function of a
* component with `RenderFlags.Create`.
*/
TemplateCreateStart,
/**
* Corresponds to the point in time after the runtime has called the template function of a
* component with `RenderFlags.Create`.
*/
TemplateCreateEnd,
/**
* Corresponds to the point in time before the runtime has called the template function of a
* component with `RenderFlags.Update`.
*/
TemplateUpdateStart,
/**
* Corresponds to the point in time after the runtime has called the template function of a
* component with `RenderFlags.Update`.
*/
TemplateUpdateEnd,
/**
* Corresponds to the point in time before the runtime has called a lifecycle hook of a component
* or directive.
*/
LifecycleHookStart,
/**
* Corresponds to the point in time after the runtime has called a lifecycle hook of a component
* or directive.
*/
LifecycleHookEnd,
/**
* Corresponds to the point in time before the runtime has evaluated an expression associated with
* an event or an output.
*/
OutputStart,
/**
* Corresponds to the point in time after the runtime has evaluated an expression associated with
* an event or an output.
*/
OutputEnd,
}
/**
* Profiler function which the runtime will invoke before and after user code.
*/
export interface Profiler {
(event: ProfilerEvent, instance: {}|null, hookOrListener?: (e?: any) => any): void;
}
let profilerCallback: Profiler|null = null;
/**
* Sets the callback function which will be invoked before and after performing certain actions at
* runtime (for example, before and after running change detection).
*
* Warning: this function is *INTERNAL* and should not be relied upon in application's code.
* The contract of the function might be changed in any release and/or the function can be removed
* completely.
*
* @param profiler function provided by the caller or null value to disable profiling.
*/
export const setProfiler = (profiler: Profiler|null) => {
profilerCallback = profiler;
};
/**
* Profiler function which wraps user code executed by the runtime.
*
* @param event ProfilerEvent corresponding to the execution context
* @param instance component instance
* @param hookOrListener lifecycle hook function or output listener. The value depends on the
* execution context
* @returns
*/
export const profiler: Profiler = function(
event: ProfilerEvent, instance: {}|null, hookOrListener?: (e?: any) => any) {
if (profilerCallback != null /* both `null` and `undefined` */) {
profilerCallback(event, instance, hookOrListener);
}
};