Source code odyssey: angular.js injector
Angular.js
Angular.js is a fasnating framework that including a lots of interesting features.
One of the unique feature in Angular.js is dependency injection,
instead of requiring and injecting the dependencies, Angular.js creates a special component to find the dependencies according to parameter names and pass it through the function:
1 |
|
Pretty cool right? In Angular, injector handle all the dependencies in controller and components in every function calls.
you can name the parameter and get the what you want.
But how does Angular do it?
Turns out there is a small core file that handle the injection In angular source:
Mini Injector
I created a simplified version of injector to demostrate how the injector works:
The process for inject dependencies can seperate to three steps:
- get list of parameter names
- get the service/componenet from list
- call the function with service/components
For getting the list of parameter names, angular use Function.toString() to get the function text,
parse the parameter text and returns the list of parameter names:
1 |
|
For getting the actual service, Angular have providers to instantiate the service, register in cache and return the service with same name.
In the mini-injector, we just pass in the plain hash providers. and injector call the function with the value from provider hash
1 |
|
After understand how injector works, we can dive into more details about angular injector:
Annotate
In angular, you can invoke the function with an array of parameter names to avoid minifier/compiler rename the params of functions.
['serviceA', 'serviceB', function(serviceA, serviceB) {}]
Also, after the function got annotated, we can get the parameter names from Function.$inject:
var fn = function(serviceA, serviceB) {}
injector.annotated(fn);
fn.$inject // ['serviceA', 'serviceB']
Provider
In Angular, it provides three ways to register provider:
- $provide.provider
$provider.provider takes a factory constractor, which includes a $get method to create actual service instance:
1 |
|
- $provide.factory
Similar to provider, but instead passing factory constractor, it takes factory method $get directly:
1 |
|
- $provide.service take a constractor method and instantiate:
1 |
|
Inside $provide.provider, it take an object or constactor function,
create a factory object with $get method and put into providerCache:
1 |
|
Injector
Injector invoke the function with objects from providers:
1 |
|
Conclusion
Dependencie injection in angular is handle by this injector pretty elegantly,
it takes the most advantage of meta programming by the flexibility of javascript.
I will continue to dig into more cool pieces in angular to write the next code odyssey article, stay tune…
Comments