Should I use
service
orfactory
? What’s the difference?
Angular makes things a little confusing by giving you the option of registering objects as services or factories. Their behavior is very similar, and some people will say that either one is fine. That’s somewhat true, but I find it easier to follow the advice of John Papa’s style guide and just stick with factories.
But you came here to learn the difference between the two, so let’s look at that.
Both of them…
-
Are Singletons – No matter which you choose, they are both singletons. Angular will create a single instance the first time it sees a dependency on your service/factory, and use that single instance forevermore.
-
Can be used to model an object with behavior – They can both have methods, internal state variables, and so on. Though the way you write that code will differ, and we’ll see how that works below.
Factories
A factory is a plain old function that returns a value. The return value is what gets injected into things that depend on the factory. A typical factory pattern in Angular is to return an object with functions as properties, like this:
Depending on your personal style, you might find it more readable to organize the code this way instead:
It’s a little easier to tell at-a-glance what the factory exposes as its public API this way.
If it seems weird to you that there are functions defined after the return
, perhaps you haven’t yet had your mind poisoned by become accustomed to JavaScript’s “hoisting” behavior. I won’t get into it here, but this is a good overview despite being a few years old.
As I mentioned above, the injected value for a factory dependency is the factory’s return value, and it doesn’t have to be an object. It could be a function (Angular’s built-in $filter
does this). That would look something like this:
Services
A service is a constructor function, and Angular will instantiate it by calling new yourService()
. This means a couple things.
- Behavior (functions) and instance variables will be properties of
this
. - You don’t need to return a value. When Angular calls
new yourService()
, it’ll receive thethis
object with all the properties you put on it.
An example service might look like this:
Notice: no return value, and methods are properties on this
.
When Angular injects this UserManager
service into a controller that depends on it, that controller will get a UserManager
that it can call functions on, e.g. UserManager.deleteUser(7)
.
Be careful with this
Since the constructed service is an object, the methods inside it can refer to this
when they’re called:
You might be tempted to call ScoreKeeper.setScore
in a promise chain, for instance if you initialized the score by grabbing it from the server: $http.get('/score').then(ScoreKeeper.setScore)
. The trouble with this is that ScoreKeeper.setScore
will be called with this
bound to null
and you’ll get errors. The better way would be $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))
, but it doesn’t read as nicely.
Whether you choose to use this
in your service methods or not, be careful how you call them.
Returning a value from a service
Due to how JavaScript constructors work, if you return a complex value (i.e. an Object) from a constructor function, the caller will get that Object instead of the this
instance.
This means that you can basically copy-paste the factory
example from above, replace factory
with service
, and it’ll work:
So when Angular constructs your service with new UserManager()
, it’ll get that api
object instead of the UserManager
instance.
This is the behavior for any complex values (objects, functions) but not for primitive types. Try it out! Open your browser console and type these in:
Then try executing each one as a regular function, and as a constructor function with new
, like so:
The best way to gain an intuitive understanding of this behavior is to play around with it.
Just Use Factories*
For the most part, just stick with using factories for everything. Their behavior is easier to understand. There’s no choice to make about whether to return a value or not, and furthermore, no bugs to be introduced if you do the wrong thing.
I still refer to them as “services” when I’m talking about injecting them as dependencies, though.
* You noticed that asterisk there?
Ok, well there are a few cases where a service is actually a better choice. As Mike mentioned in the comments, Angular’s built-in $resource
service is a great example of something that makes more sense as a service, because it actually needs to be instantiated. It models data, in addition to having prototype methods for behavior.
So if you’re writing something that seems more like a proper “object oriented” object, consider doing it as a service instead of a factory.