angular / angular

Deliver web apps with confidence 🚀
https://angular.dev
MIT License
96.16k stars 25.44k forks source link

Allow lifecycle hooks to be defined on a directive instance and not only on a prototype #38241

Open pkozlowski-opensource opened 4 years ago

pkozlowski-opensource commented 4 years ago

We tend to get repeated requests for Angular to invoke lifecycle hooks defined on a directive / component instance (and not only ones defined on a prototype). Examples of such requests (actually, reported as bugs) would be #38043 or #38087 (but I'm sure that there are more as I've seen similar issues reported in the past.

To start with, the current Angular behaviour is the result of deliberate design choices and not a simple bug / omission that we can "just fix". The current design of taking lifecycle hooks from a prototype is based on the following:

Performance considerations

As of today Angular assumes that all directives created from a given class have the same set of lifecycle functions (taken from a prototype). This assumptions allows us to make 2 significant optimisations:

Those things might sound like micr-optimisations but when you profile applications it has significant impact. Angular always worked this way as we made the assumption that the user experience (performance of a final app for the users) is more important that the developers experience here.

Inheritance

With the assumptions of a fixed set of lifecycle hooks for a directive it is easy for us to compute a new set of lifecycle hooks in the directives inheritance tree. Again, we can do those calculations only once (per directive class), without checking each individual instance.

Possible work-arrounds

@petebacondarwin suggested that one might work-arround the current design choices like so:

@Component({selector: 'app-root', template: ''})
export class AppComponent {
  title = 'test-app';
}

(AppComponent.prototype as any).ngOnInit = () => {
  console.log('init!');
};

I'm opening this issue as a feature request, mostly to track interest and ideas for another implementation that wouldn't negatively impact performance.

petebacondarwin commented 4 years ago

Another versatile workaround, but that would incur a localized performance loss just for that component, is to define the lifecycle hook as normal on the prototype but for that method to delegate to a private method you you can indeed change per instance.

VagrantAI-c commented 4 years ago

Might offer a few possibilities:

I don't know lifecycle architecture, so these above are just thoughts and assumptions: can't say at all whether it is possible to implement or is consistent with Angular approach.