Comments:"Iffy Can: Angular service or factory?"
URL:http://iffycan.blogspot.com/2013/05/angular-service-or-factory.html
tl;dr is at the end
In various AngularJS tutorials and documentation, the authors choose to use service
or factory
but don't explain why you would use one or the other. Few mention that value
and constant
are also options.
Let's see why you would use one over the other. We should also understand how providers work:
provider
Here's the source for the provider
method:
functionprovider(name,provider_){
if(isFunction(provider_)||isArray(provider_)){
provider_=providerInjector.instantiate(provider_);
}
if(!provider_.$get){
throwError('Provider '+name+' must define $get factory method.');
}
returnproviderCache[name+providerSuffix]=provider_;
}
name
is a string. provider_
can be one of three things:
Whatever the second arg to provider
is, you eventually end up with an object that has a $get
method. Here's an example showing what happens:
// You can run this// Create a module
varhippo=angular.module('hippo',[]);// Register an object provider
hippo.provider('awesome',{
$get:function(){
return'awesome data';
}
});// Get the injector (this happens behind the scenes in angular apps)
varinjector=angular.injector(['hippo','ng']);// Call a function with dependency injection
injector.invoke(function(awesome){
console.log('awesome == '+awesome);
});
Once you understand providers you will see that factory
, service
, value
and constant
are just convenience methods for making providers.
factory
Here's the source:
functionfactory(name,factoryFn){
returnprovider(name,{$get:factoryFn});
}
So it lets you shorten the awesome
provider creation code to this:
hippo.factory('awesome',function(){
return'awesome data';
})
service
Here's the source:
functionservice(name,constructor){
returnfactory(name,['$injector',function($injector){
return$injector.instantiate(constructor);
}]);
}
So it lets you make a factory that will instantiate a "class". For example:
vargandalf=angular.module('gandalf',[]);functionGandalf(){
this.color='grey';
}
Gandalf.prototype.comeBack=function(){
this.color='white';
}gandalf.service('gandalfService',Gandalf);
varinjector=angular.injector(['gandalf','ng']);
injector.invoke(function(gandalfService){
console.log(gandalfService.color);
gandalfService.comeBack()
console.log(gandalfService.color);
});
The above code will instantiate Gandalf
, but remember that everything that uses the service will get the same instance! (which is a good thing).
value
Here's the source:
functionvalue(name,value){
returnfactory(name,valueFn(value));
}
Using value
would let you shorten the awesome
provider to:
hippo.value('awesome','awesome data');
constant
Here's the source
functionconstant(name,value){
providerCache[name]=value;
instanceCache[name]=value;
}
constant
differs from value
in that it's accessible during config. Here's how you use it:
varjoe=angular.module('joe',[]);joe.constant('bobTheConstant','a value');
joe.value('samTheValue','a different value');joe.config(function(bobTheConstant){
console.log(bobTheConstant);
});joe.config(function(samTheValue){
console.log(samTheValue);
});// This will fail with "Error: Unknown provider: samTheValue from joe"
varinjector=angular.injector(['joe','ng']);
Read Module Loading & Dependencies in the Modules doc for more information on usage.
In summary
If you want your function to be called like a normal function, use factory
. If you want your function to be instantiated with the new
operator, use service
. If you don't know the difference, use factory
.
This is the (great) documentation for each function in the AngularJS source:
factory A short hand for configuring services if only `$get` method is required. service A short hand for registering service of given class. value A short hand for configuring services if the `$get` method is a constant. constant A constant value, but unlike {@link AUTO.$provide#value value} it can be injected into configuration function (other modules) and it is not interceptable by {@link AUTO.$provide#decorator decorator}.