Recently some co-workers and I were having a discussion as to whether or not AngularJS services should have state or not. We came up with some arguments for and against it a
It would probably depend on what you mean by "state", but in many cases I think the answer would be yes: services should hold state.
For example, if you have a service that is responsible for communication with an API, that service could hold the authentication state.
By the way, I'm not sure how much idempotence matters for AngularJS services - they're singletons and so inherently have some state. You could (and in some cases must) create idempotent methods on the service, but that's a separate issue.
The reason that services should not have state is that it leads to race conditions when you have multiple threads accessing the service.
A common problem with state in a service is:
Thread 1 now has the wrong value.
That being said, javascript is currently single threaded so you're not going to have thread access problems like this. However, I would be worried if I had a service where multiple asynchronous $http calls were all writing to the same service variable. If only so I could sleep better I night, I'd try to write all my service methods so they were pass-throughs for the actual data.
Instead, of maintaing the state in the service, you could consider putting the state in the backend as much as possible. Things like "authenticated" or even widths and heights could be maintained and queried for. This can open up some possibilities for allowing users to navigate away from the app, come back and find all their preferences still setup and logged in. You could store a session id in the cookie and save all this stuff on the backend.
If you did go the route of having a separate object to store state, you might be able to $emit to it from the service when something in the state has changed: how to emit events from a factory. This would have the nice side-effect of having multiple services being able to modify a unified application state because state is not being stored in any one service (or worse spread out among multiple services).
In AngularJS, services are passed in via factory function. And basically they are objects that can contain some state (e.g. for caching or storing data needed for performing their actions).
One good solution that can take both cons of having/not having state is when service (that could be actually function) that return object that contain state.
Take a look at the $http
service: you can get instance of this service calling
var x = $http({url:'...'});
And then call by
var result = x.get() //actually `$http.get` is shortcut of this operation
Same with ngResource
: using service you get object with some state that can perform desired actions.
So basically I think that is the best option: from one point you avoid 'side effects' by moving state that could be modified by actions into separate object, not stored in service itself, but can have specific state in that object to be able to store custom info (like auth information etc).
IMO yes, services CAN have states. I say "can" as a service can be thought of as something resembling a classical none client service - a provider, but it can also mean something entirely different, in angularJS. As a rootScope-y one-instance element in the app, it could be used solely to manage state, for instance. In my case, that enables me to ensure state structure is the same across many apps, and even though their individual state struct is defined for each within bootstrapping, things like session state are always the same and updated, when that module is changed.