AngularJS中的服务、提供商和工厂之间有什么区别?


当前回答

工厂:您实际在工厂内部创建对象并将其返回的工厂。service:您只有一个使用this关键字定义函数的标准函数的服务。provider:您定义了一个$get,它可以用来获取返回数据的对象。

其他回答

从AngularJS邮件列表中,我得到了一个令人惊叹的线程,它解释了服务与工厂与供应商以及它们的注入用法。编写答案:

服务

语法:module.service('serviceName',function);结果:当将serviceName声明为可注入参数时,将为您提供函数的实例。换句话说,新的FunctionYouPassedToService()。

工厂

语法:module.factory('factoryName',function);结果:当将factoryName声明为可注入参数时,将提供通过调用传递给module.factory的函数引用返回的值。

提供商

语法:module.provider('providerName',function);结果:当将providerName声明为可注入参数时,将提供(newProviderFunction())$get()。在调用$get方法之前实例化构造函数函数-ProviderFunction是传递给module.provider的函数引用。

提供程序的优点是可以在模块配置阶段进行配置。

请参阅此处获取提供的代码。

下面是Misko的进一步解释:

provide.value('a', 123);

function Controller(a) {
  expect(a).toEqual(123);
}

在这种情况下,注入器只是按原样返回值。但是如果您想计算该值呢?然后使用工厂

provide.factory('b', function(a) {
  return a*2;
});

function Controller(b) {
  expect(b).toEqual(246);
}

因此,工厂是一个负责创造价值的职能部门。注意,工厂函数可以要求其他依赖项。

但是,如果你想成为更多的OO,并拥有一个名为Greeter的类呢?

function Greeter(a) {
  this.greet = function() {
    return 'Hello ' + a;
  }
}

然后,要实例化,必须编写

provide.factory('greeter', function(a) {
  return new Greeter(a);
});

然后我们可以像这样在控制器中请求“问候者”

function Controller(greeter) {
  expect(greeter instanceof Greeter).toBe(true);
  expect(greeter.greet()).toEqual('Hello 123');
}

但这太啰嗦了。一个简短的写法是provider.service(“greeter”,greeter);

但是如果我们想在注入之前配置Greeter类呢?然后我们可以写

provide.provider('greeter2', function() {
  var salutation = 'Hello';
  this.setSalutation = function(s) {
    salutation = s;
  }

  function Greeter(a) {
    this.greet = function() {
      return salutation + ' ' + a;
    }
  }

  this.$get = function(a) {
    return new Greeter(a);
  };
});

然后我们可以这样做:

angular.module('abc', []).config(function(greeter2Provider) {
  greeter2Provider.setSalutation('Halo');
});

function Controller(greeter2) {
  expect(greeter2.greet()).toEqual('Halo 123');
}

顺便说一句,服务、工厂和价值都来自提供者。

provider.service = function(name, Class) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.instantiate(Class);
    };
  });
}

provider.factory = function(name, factory) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.invoke(factory);
    };
  });
}

provider.value = function(name, value) {
  provider.factory(name, function() {
    return value;
  });
};

另外一个澄清是,工厂可以创建函数/原语,而服务不能。看看这个基于Epokk的jsFiddle:http://jsfiddle.net/skeller88/PxdSP/1351/.

工厂返回一个可以调用的函数:

myApp.factory('helloWorldFromFactory', function() {
  return function() {
    return "Hello, World!";
  };
});

工厂还可以返回具有可调用方法的对象:

myApp.factory('helloWorldFromFactory', function() {
  return {
    sayHello: function() {
      return "Hello, World!";
    }
  };
});

该服务返回一个具有可调用方法的对象:

myApp.service('helloWorldFromService', function() {
  this.sayHello = function() {
     return "Hello, World!";
  };
});

有关详细信息,请参阅我写的关于差异的帖子:http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/

我知道很多很好的答案,但我必须分享我的使用经验1.大多数违约情况下的服务2.用于创建特定实例的服务的工厂

// factory.js ////////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];

function xFactoryImp($http) {
    var fac = function (params) {
        this._params = params; // used for query params
    };

    fac.prototype.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }
    return fac;
}
})();

// service.js //////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];

function xServiceImp($http) {  
    this._params = {'model': 'account','mode': 'list'};

    this.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }       
}
})();

并使用:

controller: ['xFactory', 'xService', function(xFactory, xService){

        // books = new instance of xFactory for query 'book' model
        var books = new xFactory({'model': 'book', 'mode': 'list'});

        // accounts = new instance of xFactory for query 'accounts' model
        var accounts = new xFactory({'model': 'account', 'mode': 'list'});

        // accounts2 = accounts variable
        var accounts2 = xService;
... 

服务与供应商与工厂:

我试图保持简单。这都是关于JavaScript的基本概念。

首先,我们来谈谈AngularJS中的服务!

什么是服务:在AngularJS中,Service只是一个单独的JavaScript对象,可以存储一些有用的方法或财产。此单例对象是根据ngApp(Angular应用程序)创建的,它在当前应用程序中的所有控制器之间共享。当Angularjs实例化服务对象时,它使用唯一的服务名称注册该服务对象。因此,每当我们需要服务实例时,Angular都会在注册表中搜索该服务名称,并返回对服务对象的引用。这样我们就可以调用方法、访问服务对象上的财产等。您可能会有疑问,是否也可以在控制器的范围对象上放置财产和方法!所以为什么需要服务对象?答案是:服务在多个控制器范围内共享。如果您将一些财产/方法放在控制器的范围对象中,它将仅对当前范围可用。但当您在服务对象上定义方法和财产时,它将全局可用,并且可以通过注入该服务在任何控制器的范围内访问。

所以,若有三个控制器作用域,让它是controllerA、controllerB和controllerC,它们都将共享同一个服务实例。

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

如何创建服务?

AngularJS提供了注册服务的不同方法。在这里,我们将集中讨论工厂(..)、服务(..)和提供者(..)三种方法;

使用此链接进行代码参考

工厂功能:

我们可以如下定义工厂函数。

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

AngularJS提供了“factory('serviceName',fnFactory)”方法,该方法包含两个参数,serviceName和一个JavaScript函数。Angular通过调用函数fnFactory()创建服务实例,如下所示。

var serviceInstace = fnFactory();

传递的函数可以定义一个对象并返回该对象。AngularJS只是将此对象引用存储到作为第一个参数传递的变量中。从fnFactory返回的任何内容都将绑定到serviceInstance。除了返回对象之外,我们还可以返回函数、值等,无论我们将返回什么,都将可用于服务实例。

例子:

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('serviceName',function fnServiceConstructor(){})

这是另一种方式,我们可以注册服务。唯一的区别是AngularJS尝试实例化服务对象的方式。这次angular使用“new”关键字并调用如下所示的构造函数。

var serviceInstance = new fnServiceConstructor();

在构造函数中,我们可以使用“this”关键字向服务对象添加财产/方法。例子:

//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()函数是创建服务的另一种方法。让我们有兴趣创建一个只向用户显示一些问候信息的服务。但我们也希望提供一个功能,用户可以设置自己的问候语。从技术上讲,我们希望创建可配置的服务。我们如何做到这一点?必须有一种方法,让应用程序可以传递他们的自定义问候消息,Angularjs将其提供给创建我们服务实例的工厂/构造函数。在这种情况下,provider()函数完成任务。使用provider()函数,我们可以创建可配置的服务。

我们可以使用下面给出的提供程序语法创建可配置的服务。

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

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

提供程序语法如何在内部工作?

1.提供程序对象是使用我们在提供程序函数中定义的构造函数创建的。

var serviceProvider = new serviceProviderConstructor();

2.我们在app.config()中传递的函数被执行。这被称为配置阶段,在这里我们有机会定制我们的服务。

configureService(serviceProvider);

3.最后通过调用serviceProvider的$get方法创建服务实例。

serviceInstance = serviceProvider.$get()

使用provide语法创建服务的示例代码:

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 ?');
  }
);

工作演示

摘要:


工厂使用返回服务实例的工厂函数。serviceInstance=fnFactory();

服务使用构造函数,Angular使用“new”关键字调用此构造函数以创建服务实例。serviceInstance=新的fnServiceConstructor();

Provider定义了providerConstructor函数,此providerConstructer函数定义了工厂函数$get。Angular调用$get()来创建服务对象。提供程序语法还有一个额外的优点,即在服务对象实例化之前对其进行配置。serviceInstance=$get();

工厂

如果给AngularJS一个函数,AngularJS将在请求工厂时缓存并注入返回值。

例子:

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

用法:

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

服务

如果给AngularJS一个函数,AngularJS将调用new来实例化它。AngularJS创建的实例将在请求服务时缓存并注入。由于new用于实例化服务,因此关键字this是有效的,并引用实例。

例子:

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

用法:

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

供应商

给AngularJS一个函数,AngularJS将调用它的$get函数。它是$get函数的返回值,将在请求服务时缓存并注入。

提供程序允许您在AngularJS调用$get方法获取可注入对象之前配置提供程序。

例子:

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

用法(作为控制器中的注射剂)

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

用法(在调用$get以创建可注射对象之前配置提供程序)

app.config(function(providerProvider) {
    providerProvider.setName('John');
});