Why does Angular have such a complex dependency injection (DI) mechanism?
I'm a front end developer with over 6 years experience, as such I've jumped between FE frameworks like Backbone, Angular (1, 2, 4), Salesforce lightning, React.
Recently, I started working on an Angular project and started understanding their DI mechanism. They have used the singleton pattern to control how a dependency can be used. A singleton is basically a class that is meant to be instantiated only once in a given context. In Angular, you can define the context based on how you provide this dependency in your app.
Note: From this point on, let's assume that I'm talking about adding an Angular service as a dependency, as that is the most common example everyone can relate to.
When you provide a service at
- Root level - A single instance of the service is shared across the app. All the modules (and components/ services within) would be using that same instance.
- Module level - A single instance of the service is shared across the module. All components and services in this module would share that same instance.
- Component level - Every component would have it's own instance. So different instances of this component won't have access to the public data of the service of each other.
To add more to it, how a service is resolved and what value it would use, is another lookup across the app hierarchy at the element (component/ directive) and module level. This is explained in depth, here.
While I spent a Sunday understanding this, I couldn't help pondering what is the need for such complexity? In my opinion, using the singleton pattern is forcing classic OOP language concepts into JavaScript. I understand that there are some complex use cases for library authors where this would help, but majority of the users won't need this. A lot of Angular FE developers use services (Angular services) for state management. This DI system forces them to follow a class based singleton approach.
Why could Angular not use the native Ecmascript module system available since ES2015 / ES6?
What is the merit of having such complexity?