ChatGPT解决这个技术问题 Extra ChatGPT

angular.service vs angular.factory

I have seen both angular.factory() and angular.service() used to declare services; however, I cannot find angular.service anywhere in official documentation.

What is the difference between the two methods? Which should be used for what (assuming they do different things)?

possible duplicate of confused about service vs factory
I searched for "[angularjs] service factory", but I also had remembered that there was already a question about it (because I thought about writing that/this question myself at one point).
In a search, do the square-brackets signify a tag?
@Jacob Square Brackets are narrowing down your search. [angularjs] directives -- will search for 'directives' for questions already tagged with angularjs.
@Mahbub In other words, "yes" :)

C
Community
  angular.service('myService', myServiceFunction);
  angular.factory('myFactory', myFactoryFunction);

I had trouble wrapping my head around this concept until I put it to myself this way:

Service: the function that you write will be new-ed:

  myInjectedService  <----  new myServiceFunction()

Factory: the function (constructor) that you write will be invoked:

  myInjectedFactory  <---  myFactoryFunction()

What you do with that is up to you, but there are some useful patterns...

Such as writing a service function to expose a public API:

function myServiceFunction() {
  this.awesomeApi = function(optional) {
    // calculate some stuff
    return awesomeListOfValues;
  }
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.awesome = myInjectedService.awesomeApi();

Or using a factory function to expose a public API:

function myFactoryFunction() {
  var aPrivateVariable = "yay";

  function hello() {
    return "hello mars " + aPrivateVariable;
  }
  
  // expose a public API
  return {
    hello: hello
  };
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.hello = myInjectedFactory.hello();

Or using a factory function to return a constructor:

function myFactoryFunction() {
    return function() {
        var a = 2;
        this.a2 = function() {
            return a*2;
        };
    };
}
---------------------------------------------------------------------------------
// Injected in your controller
var myShinyNewObject = new myInjectedFactory();
$scope.four = myShinyNewObject.a2();

Which one to use?...

You can accomplish the same thing with both. However, in some cases the factory gives you a little bit more flexibility to create an injectable with a simpler syntax. That's because while myInjectedService must always be an object, myInjectedFactory can be an object, a function reference, or any value at all. For example, if you wrote a service to create a constructor (as in the last example above), it would have to be instantiated like so:

var myShinyNewObject = new myInjectedService.myFunction()

which is arguably less desirable than this:

var myShinyNewObject = new myInjectedFactory();

(But you should be wary about using this type of pattern in the first place because new-ing objects in your controllers creates hard-to-track dependencies that are difficult to mock for testing. Better to have a service manage a collection of objects for you than use new() wily-nilly.)

One more thing, they are all Singletons...

Also keep in mind that in both cases, angular is helping you manage a singleton. Regardless of where or how many times you inject your service or function, you will get the same reference to the same object or function. (With the exception of when a factory simply returns a value like a number or string. In that case, you will always get the same value, but not a reference.)


Would it be better to call it an object constructor than Newable?
@Hugo, I was demonstrating that you can effectively accomplish the same thing with both, it's just that the syntax will differ.
I'm not sure how many times I'll have to read about the difference between service and factory before I'm convinced both of them are necessary
We already have a verb to say "to new", it's "instantiate". Just for reference. :)
Factories are functions that are invoked, so they can return anything. On the other hand, services are instantiated by angular via new fn(), so they must return an instance.
K
Kirk Strobeck

Simply put ..

const user = { firstName: 'john' }; // Factory const addLastNameFactory = (user, lastName) => ({ ...user, lastName, }); console.log(addLastNameFactory(user, 'doe')); // Service const addLastNameService = (user, lastName) => { user.lastName = lastName; // BAD! Mutation return user; }; console.log(addLastNameService(user, 'doe'));


Dude, thank you. Not that the details of the other answers are not valid, but some times you need the 10 sec version.
Just have the service function return nothing. The this.name = ... is enough to show that it is exposing an API.
However if you do return and object it will use that instead of this. jsfiddle.net/Ne5P8/1221
@MrB, that's a normal JavaScript feature, not specific to Angular or this question's context.
@Om Shankar, The answer above is showing that the difference is the use of this vs a returned object. I was showing that "THIS" is the default value that will be used with a service however if you return a value it will act almost exactly like a factory. However on the flip side a factory appears to require a returned value else an error will occur - (shown in this example - jsfiddle.net/hmoc0q3v/1).
C
Community

Here are the primary differences:

Services

Syntax: module.service( 'serviceName', function );

Result: When declaring serviceName as an injectable argument you will be provided with the instance of a function passed to module.service.

Usage: Could be useful for sharing utility functions that are useful to invoke by simply appending ( ) to the injected function reference. Could also be run with injectedArg.call( this ) or similar.

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.

Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances.

Here is example using services and factory. Read more about AngularJS Service vs Factory.

You can also check the AngularJS documentation and similar question on stackoverflow confused about service vs factory.


I disagree with your example usage of a factory. Both services and factories(assuming a function is returned. It could just be a value or an object) can be new'ed. In fact a service is the only option that is guaranteed to be new'able as you are provided a function instance. I would say the benefit of using a FACTORY over a SERVICE is that it allows some control over access to properties - private & public per se whereas all of the properties of the service are by nature exposed. And I think of a provider as a factory of a factory - only it is injectable and configurable at config time.
@DrewR Thanks for your comment, I found a good example of public and private methods using a Factory: stackoverflow.com/a/14904891/65025
I have to agree with @DrewR on this one, actually. I've used factories to return objects before, but honestly at this point it might be worth it to just use $providers all the time.
service is automatic instantiating the constructor, right?
@DrewR - From my understanding, it's true that you can achieve the same new'able effect from service like you can with a factory, but it's not what it's meant for. It's main goal is when you just want to return some utility object and for that it provides a more suitable syntax - you can simply write this.myFunc = function(){} in your service (saves you from writing code to create the object like you'd have to do with a factory).
Z
Zanon

TL;DR 1) When you’re using a Factory you create an object, add properties to it, then return that same object. When you pass this factory into your controller, those properties on the object will now be available in that controller through your factory.

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.artist = myFactory.getArtist();
});

app.factory('myFactory', function(){
  var _artist = 'Shakira';
  var service = {};

  service.getArtist = function(){
    return _artist;
  }

  return service;
});

2) When you’re using Service, Angular instantiates it behind the scenes with the ‘new’ keyword. Because of that, you’ll 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.

app.controller('myServiceCtrl', function($scope, myService){
  $scope.artist = myService.getArtist();
});

app.service('myService', function(){
  var _artist = 'Nelly';
  this.getArtist = function(){
    return _artist;
  }
});

Non TL;DR

1) Factory Factories are the most popular way to create and configure a service. There’s really not much more than what the TL;DR said. You just create an object, add properties to it, then return that same object. Then when you pass the factory into your controller, those properties on the object will now be available in that controller through your factory. A more extensive example is below.

app.factory('myFactory', function(){
  var service = {};
  return service;
});

Now whatever properties we attach to ‘service’ will be available to us when we pass ‘myFactory’ into our controller.

Now let’s add some ‘private’ variables to our callback function. These won’t be directly accessible from the controller, but we will eventually set up some getter/setter methods on ‘service’ to be able to alter these ‘private’ variables when needed.

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
   _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK';
    return _finalUrl
  }

  return service;
});

Here you’ll notice we’re not attaching those variables/function to ‘service’. We’re simply creating them in order to either use or modify them later.

baseUrl is the base URL that the iTunes API requires

_artist is the artist we wish to lookup

_finalUrl is the final and fully built URL to which we’ll make the call to iTunes makeUrl is a function that will create and return our iTunes friendly URL.

Now that our helper/private variables and function are in place, let’s add some properties to the ‘service’ object. Whatever we put on ‘service’ we’ll be able to directly use in whichever controller we pass ‘myFactory’ into.

We are going to create setArtist and getArtist methods that simply return or set the artist. We are also going to create a method that will call the iTunes API with our created URL. This method is going to return a promise that will fulfill once the data has come back from the iTunes API. If you haven’t had much experience using promises in Angular, I highly recommend doing a deep dive on them.

Below setArtist accepts an artist and allows you to set the artist. getArtist returns the artist callItunes first calls makeUrl() in order to build the URL we’ll use with our $http request. Then it sets up a promise object, makes an $http request with our final url, then because $http returns a promise, we are able to call .success or .error after our request. We then resolve our promise with the iTunes data, or we reject it with a message saying ‘There was an error’.

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  service.setArtist = function(artist){
    _artist = artist;
  }

  service.getArtist = function(){
    return _artist;
  }

  service.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

  return service;
});

Now our factory is complete. We are now able to inject ‘myFactory’ into any controller and we’ll then be able to call our methods that we attached to our service object (setArtist, getArtist, and callItunes).

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.data = {};
  $scope.updateArtist = function(){
    myFactory.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myFactory.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

In the controller above we’re injecting in the ‘myFactory’ service. We then set properties on our $scope object that are coming from data from ‘myFactory’. The only tricky code above is if you’ve never dealt with promises before. Because callItunes is returning a promise, we are able to use the .then() method and only set $scope.data.artistData once our promise is fulfilled with the iTunes data. You’ll notice our controller is very ‘thin’. All of our logic and persistent data is located in our service, not in our controller. 2) Service Perhaps the biggest thing to know when dealing with creating a Service is that that it’s instantiated with the ‘new’ keyword. For you JavaScript gurus this should give you a big hint into the nature of the code. For those of you with a limited background in JavaScript or for those who aren’t too familiar with what the ‘new’ keyword actually does, let’s review some JavaScript fundamentals that will eventually help us in understanding the nature of a Service.

To really see the changes that occur when you invoke a function with the ‘new’ keyword, let’s create a function and invoke it with the ‘new’ keyword, then let’s show what the interpreter does when it sees the ‘new’ keyword. The end results will both be the same.

First let’s create our Constructor.

var Person = function(name, age){
  this.name = name;
  this.age = age;
}

This is a typical JavaScript constructor function. Now whenever we invoke the Person function using the ‘new’ keyword, ‘this’ will be bound to the newly created object.

Now let’s add a method onto our Person’s prototype so it will be available on every instance of our Person ‘class’.

Person.prototype.sayName = function(){
  alert('My name is ' + this.name);
}

Now, because we put the sayName function on the prototype, every instance of Person will be able to call the sayName function in order alert that instance’s name.

Now that we have our Person constructor function and our sayName function on its prototype, let’s actually create an instance of Person then call the sayName function.

var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'

So all together the code for creating a Person constructor, adding a function to it’s prototype, creating a Person instance, and then calling the function on its prototype looks like this.

var Person = function(name, age){
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  alert('My name is ' + this.name);
}
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'

Now let’s look at what actually is happening when you use the ‘new’ keyword in JavaScript. First thing you should notice is that after using ‘new’ in our example, we’re able to call a method (sayName) on ‘tyler’ just as if it were an object - that’s because it is. So first, we know that our Person constructor is returning an object, whether we can see that in the code or not. Second, we know that because our sayName function is located on the prototype and not directly on the Person instance, the object that the Person function is returning must be delegating to its prototype on failed lookups. In more simple terms, when we call tyler.sayName() the interpreter says “OK, I’m going to look on the ‘tyler’ object we just created, locate the sayName function, then call it. Wait a minute, I don’t see it here - all I see is name and age, let me check the prototype. Yup, looks like it’s on the prototype, let me call it.”.

Below is code for how you can think about what the ‘new’ keyword is actually doing in JavaScript. It’s basically a code example of the above paragraph. I’ve put the ‘interpreter view’ or the way the interpreter sees the code inside of notes.

var Person = function(name, age){
  //The line below this creates an obj object that will delegate to the person's prototype on failed lookups.
  //var obj = Object.create(Person.prototype);

  //The line directly below this sets 'this' to the newly created object
  //this = obj;

  this.name = name;
  this.age = age;

  //return this;
}

Now having this knowledge of what the ‘new’ keyword really does in JavaScript, creating a Service in Angular should be easier to understand.

The biggest thing to understand when creating a Service is knowing that Services are instantiated with the ‘new’ keyword. Combining that knowledge with our examples above, you should now recognize that you’ll be attaching your properties and methods directly to ‘this’ which will then be returned from the Service itself. Let’s take a look at this in action.

Unlike what we originally did with the Factory example, we don’t need to create an object then return that object because, like mentioned many times before, we used the ‘new’ keyword so the interpreter will create that object, have it delegate to it’s prototype, then return it for us without us having to do the work.

First things first, let’s create our ‘private’ and helper function. This should look very familiar since we did the exact same thing with our factory. I won’t explain what each line does here because I did that in the factory example, if you’re confused, re-read the factory example.

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
});

Now, we’ll attach all of our methods that will be available in our controller to ‘this’.

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.setArtist = function(artist){
    _artist = artist;
  }

  this.getArtist = function(){
    return _artist;
  }

  this.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

});

Now just like in our factory, setArtist, getArtist, and callItunes will be available in whichever controller we pass myService into. Here’s the myService controller (which is almost exactly the same as our factory controller).

app.controller('myServiceCtrl', function($scope, myService){
  $scope.data = {};
  $scope.updateArtist = function(){
    myService.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myService.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

Like I mentioned before, once you really understand what ‘new’ does, Services are almost identical to factories in Angular.


You might want to provide a link directly to your blog. tylermcginnis.com/angularjs-factory-vs-service-vs-provider I found that a little easier to read.
Nothin wrong with repeating your blog here, but I agree that is a greta blog post.
Good detail explanation of what each one does under the hood, but still not clear why and when would someone choose to use a Service over a Factory. In other words, when will I prefer to have a newed object vs. the one returned by a factory. I think this is the greatest confusion.
Basically, if you want to create a persistent connection to a remote service, like the iTunes API mentioned in the example with a constant connection (connection state, call history, data storage), you can go with Factory. If you implement it as a Service, then every time you want something from the API you'll have re-create the connection and can't really store anything in it. Because every time you re-create the service, you'll get a blank/default object.
I don't think that is correct, @Aznim. Like others have said, both provide singletons.
s
superluminary

The clue is in the name

Services and factories are similar to one another. Both will yield a singleton object that can be injected into other objects, and so are often used interchangeably.

They are intended to be used semantically to implement different design patterns.

Services are for implementing a service pattern

A service pattern is one in which your application is broken into logically consistent units of functionality. An example might be an API accessor, or a set of business logic.

This is especially important in Angular because Angular models are typically just JSON objects pulled from a server, and so we need somewhere to put our business logic.

Here is a Github service for example. It knows how to talk to Github. It knows about urls and methods. We can inject it into a controller, and it will generate and return a promise.

(function() {
  var base = "https://api.github.com";

  angular.module('github', [])
    .service('githubService', function( $http ) {
      this.getEvents: function() {
        var url = [
          base,
          '/events',
          '?callback=JSON_CALLBACK'
        ].join('');
        return $http.jsonp(url);
      }
    });
  )();

Factories implement a factory pattern

Factories, on the other hand are intended to implement a factory pattern. A factory pattern in one in which we use a factory function to generate an object. Typically we might use this for building models. Here is a factory which returns an Author constructor:

angular.module('user', [])
  .factory('User', function($resource) {
    var url = 'http://simple-api.herokuapp.com/api/v1/authors/:id'
    return $resource(url);
  })

We would make use of this like so:

angular.module('app', ['user'])
  .controller('authorController', function($scope, User) {
    $scope.user = new User();
  })

Note that factories also return singletons.

Factories can return a constructor

Because a factory simply returns an object, it can return any type of object you like, including a constructor function, as we see above.

Factories return an object; services are newable

Another technical difference is in the way services and factories are composed. A service function will be newed to generate the object. A factory function will be called and will return the object.

Services are newable constructors.

Factories are simply called and return an object.

This means that in a service, we append to "this" which, in the context of a constructor, will point to the object under construction.

To illustrate this, here is the same simple object created using a service and a factory:

angular.module('app', [])
  .service('helloService', function() {
    this.sayHello = function() {
      return "Hello!";
    }
  })
  .factory('helloFactory', function() {
    return {
      sayHello: function() {
        return "Hello!";
      }
    }
  });

great explanation, thank you! also there is a type in Factories sample code where Author injector parameter should be Person.
Thanks @mik-T, I fixed the typos.
Your use of the service pattern is incorrect - this should be a factory. If you call .factory() instead of .service() you'll see that it works exactly the same. The service pattern is meant to be supplied with a constructor function, not a function that returns a new object. Angular (effectively) calls "new" on your constructor function. The only reason your service works is that in if you call "new" on a constructor function that returns an object, you actually get back the returned object rather than the constructed one. And factories can be used to create anything you want, not just models.
L
Luis Perez

All the answers here seem to be around service and factory, and that's valid since that was what was being asked about. But it's also important to keep in mind that there are several others including provider(), value(), and constant().

The key to remember is that each one is a special case of the other. Each special case down the chain allowing you to do the same thing with less code. Each one also having some additional limitation.

To decide when to use which you just see which one allows you to do what you want in less code. Here is an image illustrating just how similar they are:

https://i.stack.imgur.com/CkdHl.png

For a complete step by step breakdown and quick reference of when to use each you can visit the blog post where I got this image from:

http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


@jacob maybe so, but I think the overall concept of not only when to use each, but that they are all essentially variations of the same thing is an important one.
@LuisPerez The link to your blog and the video explaining the difference it is really great. It is easier to understand with those examples from the video :)
p
pixelbits

app.factory('fn', fn) vs. app.service('fn',fn)

Construction

With factories, Angular will invoke the function to get the result. It is the result that is cached and injected.

 //factory
 var obj = fn();
 return obj;

With services, Angular will invoke the constructor function by calling new. The constructed function is cached and injected.

  //service
  var obj = new fn();
  return obj;

Implementation

Factories typically return an object literal because the return value is what's injected into controllers, run blocks, directives, etc

  app.factory('fn', function(){
         var foo = 0;
         var bar = 0;
         function setFoo(val) {
               foo = val;
         }
         function setBar (val){
               bar = val;
         }
         return {
                setFoo: setFoo,
                serBar: setBar
         }
  });

Service functions typically do not return anything. Instead, they perform initialization and expose functions. Functions can also reference 'this' since it was constructed using 'new'.

app.service('fn', function () {
         var foo = 0;
         var bar = 0;
         this.setFoo = function (val) {
               foo = val;
         }
         this.setBar = function (val){
               bar = val;
         }
});

Conclusion

When it comes to using factories or services they are both very similar. They are injected into a controllers, directives, run block, etc, and used in client code in pretty much the same way. They are also both singletons - meaning the same instance is shared between all places where the service/factory is injected.

So which should you prefer? Either one - they are so similar that the differences are trivial. If you do choose one over the other, just be aware how they are constructed, so that you can implement them properly.


Service functions don't "not return anything", they implicitly return the constructed object IF you don't specify your own return statement (in the latter case the object you returned is what will be created and cached, similar to a factory).
I think you're misinterpreting it... When I say return, I mean from the point of view from the service function implementation
are you sure factory is also single town?
p
ps.

I have spent some time trying to figure out the difference.

And i think the factory function uses the module pattern and service function uses the standard java script constructor pattern.


D
Dan King

The factory pattern is more flexible as it can return functions and values as well as objects.

There isn't a lot of point in the service pattern IMHO, as everything it does you can just as easily do with a factory. The exceptions might be:

If you care about the declared type of your instantiated service for some reason - if you use the service pattern, your constructor will be the type of the new service.

If you already have a constructor function that you're using elsewhere that you also want to use as a service (although probably not much use if you want to inject anything into it!).

Arguably, the service pattern is a slightly nicer way to create a new object from a syntax point of view, but it's also more costly to instantiate. Others have indicated that angular uses "new" to create the service, but this isn't quite true - it isn't able to do that because every service constructor has a different number of parameters. What angular actually does is use the factory pattern internally to wrap your constructor function. Then it does some clever jiggery pokery to simulate javascript's "new" operator, invoking your constructor with a variable number of injectable arguments - but you can leave out this step if you just use the factory pattern directly, thus very slightly increasing the efficiency of your code.


Services are more efficient to construct than Factories as factories use relatively expensive closures and services (classes) can take advantage of prototype.
@jacob Not sure what you mean about closures? The factory is just a function that returns an object. You only have to use a closure if your returned object requires "private" state. You'd still have to do the same thing if you used a constructor (service). I take your point about prototype though - although you could still do this in a factory if you wanted to.
function MyFactory(dep1) { var $$foo = 'bar', factory = {}; Object.defineProperties(factory.prototype, { foo: { value: $$foo } }); return factory; } function MyService(dep1) { var $$foo = 'bar'; Object.defineProperties(MyService.prototype, { foo: { value: $$foo } }); } Whilst both MyFactory and MyService use prototype, MyFactory still takes a performance hit having to construct the object that's being returned. In both examples, they have privates, but in MyService there's relatively no performance difference.
For me, the difference is whether I want to use the factory directly without a method: MyFactory(someArgument) (ex $http()). That is not possible with a service as you'd be referencing the constructor: MyService(someArgument).
On object construction time, I don't really see how factory = {} is a performance hit, more than javascript initialising "this" for you when it calls your constructor? And I think the bigger performance hit is on the angular side when it wraps your constructor in a factory and then has to jump through hoops in order to simulate "new" so it can inject your dependencies.