Many developers ask this question, trying to understand this dependency injection, other differences, advantages and disadvantages of these AngularJS objects. In this article I will try to explain in details everything we know about the providers, services and factories.
The answer come to be around service and factory, and this difference between them is like the difference between some function and an object.
Factory Provider
- Gives us the function’s return value ie. You create an object, add properties to it, then return that same object. When you pass this service into your controller, those properties on the object will now be available in that controller through your factory (hypothetically)
- Singleton
- Reusable components
- Can use other dependencies
- Usually used when the service instance requires complex creation logic
- Used for non configurable services
- If you’re using an object, you could use the factory provider
Service Provider
- Gives us the instance of a function (object). You instantiated with the ‘new’ keyword and you will add properties to ‘this’ and the service will return ‘this’. When you pass the service into your controller, those properties on ‘this’ will now be available on that controller through your service (hypothetically)
- Singleton and will only be created once
- Reusable components
- Dependencies are injected as constructor arguments
- Used for simple creation logic
- If you’re using a class you could use the service provider
Services
Syntax: module.service('serviceName', function);
Result: When declaring serviceName as an injectable argument you will be provided with an instance of the function. In other words new FunctionYouPassToService()
Factories
Syntax: module.factory('factoryName', function);
Result: When declaring factoryName as an injectable argument you will be provided with the value that is returned by invoking the function reference passed to module.factory
Providers
Syntax: module.provider('providerName', function);
Result: When declaring providerName as an injectable argument you will be provided with (new ProviderFunction()).$get(). The constructor function is instantiated before the $get method is called – ProviderFunction is the function reference passed to module.provider Providers have the advantage that they can be configured during the module configuration phase. Example:
1 |
provide.value( 'variable' , 123); |
2 |
function Controller(variable) { |
3 |
expect(variable).toEqual(123); |
In this case the injector simply returns the value as is. But what if you want to compute the value? Then use a factory:
1 |
provide.factory( 'myfactory' , function (variable) { |
4 |
function Controller(myfactory) { |
5 |
expect(myfactory).toEqual(246); |
So factory is a function which is responsible for creating the value. Notice that the factory function can ask for other dependencies. But what if you want to be more OO and have a class called Greeter?
1 |
function Greeter(name) { |
2 |
this .greet = function () { |
3 |
return 'Hello ' + name; |
Then to instantiate you would have to write
1 |
provide.factory( 'greeter' , function (name) { |
2 |
return new Greeter(name); |
Then we could ask for ‘greeter’ in controller like this
1 |
function Controller(greeter) { |
2 |
expect(greeter instanceof Greeter).toBe( true ); |
3 |
expect(greeter.greet()).toEqual( 'Hello John' ); |
But that is way too wordy. A shorter way to write this would be provider.service(‘greeter’, Greeter); But what if we wanted to configure the Greeter class before the injection? Then we could write
01 |
provide.provider( 'greeter2' , function () { |
02 |
var salutation = 'Hello' ; |
03 |
this .setSalutation = function (s) { |
06 |
function Greeter(name) { |
07 |
this .greet = function () { |
08 |
return salutation + ' ' + name; |
11 |
this .$get = function (name) { |
12 |
return new Greeter(name); |
Then we can do this:
1 |
angular.module( 'abc' , []).config( function (greeter2Provider) { |
2 |
greeter2Provider.setSalutation( 'Hola' ); |
4 |
function Controller(greeter2) { |
5 |
expect(greeter2.greet()).toEqual( 'Hola John' ); |
As a side note, service, factory, and value are all derived from provider.
01 |
provider.service = function (name, Class) { |
02 |
provider.provide(name, function () { |
03 |
this .$get = function ($injector) { |
04 |
return $injector.instantiate(Class); |
08 |
provider.factory = function (name, factory) { |
09 |
provider.provide(name, function () { |
10 |
this .$get = function ($injector) { |
11 |
return $injector.invoke(factory); |
15 |
provider.value = function (name, value) { |
16 |
provider.factory(name, function () { |
Summary:
Factory use a factory function which return a service instance. serviceInstance = fnFactory(); Service use a constructor function and Angular invoke this constructor function using ‘new’ keyword for creating the service instance. serviceInstance = new fnServiceConstructor(); Provider defines a providerConstructor function, this providerConstructor function defines a factory function $get . Angular calls $get() to create the service object. Provider syntax has an added advantage of configuring the service object before it get instantiated. serviceInstance = $get();