AngularJS: Service vs provider vs factory

2018-12-30 23:40发布

What are the differences between a Service, Provider and Factory in AngularJS?

30条回答
还给你的自由
2楼-- · 2018-12-30 23:50

For me, the revelation came when I realized that they all work the same way: by running something once, storing the value they get, and then cough up that same stored value when referenced through dependency injection.

Say we have:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

The difference between the three is that:

  1. a's stored value comes from running fn.
  2. b’s stored value comes from newing fn.
  3. c’s stored value comes from first getting an instance by newing fn, and then running a $get method of the instance.

Which means there’s something like a cache object inside AngularJS, whose value of each injection is only assigned once, when they've been injected the first time, and where:

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

This is why we use this in services, and define a this.$get in providers.

查看更多
与风俱净
3楼-- · 2018-12-30 23:50

Service vs provider vs factory:

I am trying to keep it simple. It's all about basic JavaScript concept.

First of all, let's talk about services in AngularJS!

What is Service: In AngularJS, Service is nothing but a singleton JavaScript object which can store some useful methods or properties. This singleton object is created per ngApp(Angular app) basis and it is shared among all the controllers within current app. When Angularjs instantiate a service object, it register this service object with a unique service name. So each time when we need service instance, Angular search the registry for this service name, and it returns the reference to service object. Such that we can invoke method, access properties etc on the service object. You may have question whether you can also put properties, methods on scope object of controllers! So why you need service object? Answers is: services are shared among multiple controller scope. If you put some properties/methods in a controller's scope object , it will be available to current scope only. But when you define methods, properties on service object, it will be available globally and can be accessed in any controller's scope by injecting that service.

So if there are three controller scope, let it be controllerA, controllerB and controllerC, all will share same service instance.

<div ng-controller='controllerA'>
    <!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
    <!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
    <!-- controllerC scope -->
</div>

How to create a service?

AngularJS provide different methods to register a service. Here we will concentrate on three methods factory(..),service(..),provider(..);

Use this link for code reference

Factory function:

We can define a factory function as below.

factory('serviceName',function fnFactory(){ return serviceInstance;})

AngularJS provides 'factory('serviceName', fnFactory)' method which takes two parameter, serviceName and a JavaScript function. Angular creates service instance by invoking the function fnFactory() such as below.

var serviceInstace = fnFactory();

The passed function can define a object and return that object. AngularJS simply stores this object reference to a variable which is passed as first argument. Anything which is returned from fnFactory will be bound to serviceInstance . Instead of returning object , we can also return function, values etc, Whatever we will return , will be available to service instance.

Example:

var app= angular.module('myApp', []);
//creating service using factory method
app.factory('factoryPattern',function(){
  var data={
    'firstName':'Tom',
    'lastName':' Cruise',
    greet: function(){
      console.log('hello!' + this.firstName + this.lastName);
    }
  };

  //Now all the properties and methods of data object will be available in our service object
  return data;
});

Service Function:

service('serviceName',function fnServiceConstructor(){})

It's the another way, we can register a service. The only difference is the way AngularJS tries to instantiate the service object. This time angular uses 'new' keyword and call the constructor function something like below.

var serviceInstance = new fnServiceConstructor();

In the constructor function we can use 'this' keyword for adding properties/methods to the service object. example:

//Creating a service using the service method
var app= angular.module('myApp', []);
app.service('servicePattern',function(){
  this.firstName ='James';
  this.lastName =' Bond';
  this.greet = function(){
    console.log('My Name is '+ this.firstName + this.lastName);
  };
});

Provider function:

Provider() function is the another way for creating services. Let we are interested to create a service which just display some greeting message to the user. But we also want to provide a functionality such that user can set their own greeting message. In technical terms we want to create configurable services. How can we do this ? There must be a way, so that app could pass their custom greeting messages and Angularjs would make it available to factory/constructor function which create our services instance. In such a case provider() function do the job. using provider() function we can create configurable services.

We can create configurable services using provider syntax as given below.

/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});

/*step2:configure the service */
app.config(function configureService(serviceProvider){});

How does provider syntax internally work?

1.Provider object is created using constructor function we defined in our provider function.

var serviceProvider = new serviceProviderConstructor();

2.The function we passed in app.config(), get executed. This is called config phase, and here we have a chance to customize our service.

configureService(serviceProvider);

3.Finally service instance is created by calling $get method of serviceProvider.

serviceInstance = serviceProvider.$get()

Sample code for creating service using provide syntax:

var app= angular.module('myApp', []);
app.provider('providerPattern',function providerConstructor(){
  //this function works as constructor function for provider
  this.firstName = 'Arnold ';
  this.lastName = ' Schwarzenegger' ;
  this.greetMessage = ' Welcome, This is default Greeting Message' ;
  //adding some method which we can call in app.config() function
  this.setGreetMsg = function(msg){
    if(msg){
      this.greetMessage =  msg ;
    }
  };

  //We can also add a method which can change firstName and lastName
  this.$get = function(){
    var firstName = this.firstName;
    var lastName = this.lastName ;
    var greetMessage = this.greetMessage;
    var data={
       greet: function(){
         console.log('hello, ' + firstName + lastName+'! '+ greetMessage);
       }
    };
    return data ;
  };
});

app.config(
  function(providerPatternProvider){
    providerPatternProvider.setGreetMsg(' How do you do ?');
  }
);

Working Demo

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();

查看更多
呛了眼睛熬了心
4楼-- · 2018-12-30 23:50

As pointed out by several people here correctly a factory, provider, service, and even value and constant are versions of the same thing. You can dissect the more general provider into all of them. Like so:

enter image description here

Here's the article this image is from:

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

查看更多
梦该遗忘
5楼-- · 2018-12-30 23:51

My understanding is very simple below.

Factory: You simply create an object inside of the factory and return it.

Service:

You just have a standard function that uses this keyword to define a function.

Provider:

There is a $get object that you define and it can be used to get the object that returns data.

查看更多
春风洒进眼中
6楼-- · 2018-12-30 23:52

Factory

You give AngularJS a function, AngularJS will cache and inject the return value when the factory is requested.

Example:

app.factory('factory', function() {
    var name = '';
    // Return value **is** the object that will be injected
    return {
        name: name;
    }
})

Usage:

app.controller('ctrl', function($scope, factory) {
     $scope.name = factory.name;
});

Service

You give AngularJS a function, AngularJS will call new to instantiate it. It is the instance that AngularJS creates that will be cached and injected when the service is requested. Since new was used to instantiate the service, the keyword this is valid and refers to the instance.

Example:

app.service('service', function() {
     var name = '';
     this.setName = function(newName) {
         name = newName;
     }
     this.getName = function() {
         return name;
     }
});

Usage:

app.controller('ctrl', function($scope, service) {
   $scope.name = service.getName();
});

Provider

You give AngularJS a function, and AngularJS will call its $get function. It is the return value from the $get function that will be cached and injected when the service is requested.

Providers allow you to configure the provider before AngularJS calls the $get method to get the injectible.

Example:

app.provider('provider', function() {
     var name = '';
     this.setName = function(newName) {
          name = newName;
     }
     this.$get = function() {
         return {
            name: name
         }
     }
})

Usage (as an injectable in a controller)

app.controller('ctrl', function($scope, provider) {
    $scope.name = provider.name;
});

Usage (configuring the provider before $get is called to create the injectable)

app.config(function(providerProvider) {
    providerProvider.setName('John');
});
查看更多
若你有天会懂
7楼-- · 2018-12-30 23:52

I noticed something interesting when playing around with providers.

Visibility of injectables is different for providers than it is for services and factories. If you declare an AngularJS "constant" (for example, myApp.constant('a', 'Robert');), you can inject it into services, factories, and providers.

But if you declare an AngularJS "value" (for example., myApp.value('b', {name: 'Jones'});), you can inject it into services and factories, but NOT into the provider-creating function. You can, however, inject it into the $get function that you define for your provider. This is mentioned in the AngularJS documentation, but it's easy to miss. You can find it on the %provide page in the sections on the value and constant methods.

http://jsfiddle.net/R2Frv/1/

<div ng-app="MyAppName">
    <div ng-controller="MyCtrl">
        <p>from Service: {{servGreet}}</p>
        <p>from Provider: {{provGreet}}</p>
    </div>
</div>
<script>
    var myApp = angular.module('MyAppName', []);

    myApp.constant('a', 'Robert');
    myApp.value('b', {name: 'Jones'});

    myApp.service('greetService', function(a,b) {
        this.greeter = 'Hi there, ' + a + ' ' + b.name;
    });

    myApp.provider('greetProvider', function(a) {
        this.firstName = a;
        this.$get = function(b) {
            this.lastName = b.name;
            this.fullName = this.firstName + ' ' + this.lastName;
            return this;
        };
    });

    function MyCtrl($scope, greetService, greetProvider) {
        $scope.servGreet = greetService.greeter;
        $scope.provGreet = greetProvider.fullName;
    }
</script>
查看更多
登录 后发表回答