AngularJS:服务vs供应商vs工厂

AngularJS中的ServiceProviderFactory有什么区别?

781416 次浏览

从AngularJS邮件列表中,我得到了一个惊人的线程,它解释了服务与工厂与提供者及其注入用法。编译答案:

服务

语法:module.service( 'serviceName', function );
结果:将serviceName声明为可注入参数您将获得该函数的一个实例。换句话说new FunctionYouPassedToService()时。

工厂

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

提供商

语法:module.provider( 'providerName', function );
结果:当将ProviderName声明为可注入参数您将获得(new ProviderFunction()).$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);}

所以factory是一个负责创建值的函数。请注意,工厂函数可以要求其他依赖项。

但是如果你想更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');}

作为旁注,servicefactoryvalue都派生自提供者。

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

我在和供应商玩的时候注意到了一些有趣的事情。

提供者对注入的可见性与服务和工厂的可见性不同。如果您声明一个AngularJS“常量”(例如,myApp.constant('a', 'Robert');),您可以将其注入服务、工厂和提供者。

但是,如果您声明了AngularJS“值”(例如.,myApp.value('b', {name: 'Jones'});),您可以将其注入服务和工厂,但不能注入提供程序创建函数。但是,您可以将其注入为提供程序定义的$get函数中。这在AngularJS留档中有所提及,但很容易错过。您可以在值和常量方法部分的%提供页面上找到它。

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>

JS小提琴演示

factory/service/provider的“Hello world”示例:

var myApp = angular.module('myApp', []);
//service style, probably the simplest onemyApp.service('helloWorldFromService', function() {this.sayHello = function() {return "Hello, World!";};});
//factory style, more involved but more sophisticatedmyApp.factory('helloWorldFromFactory', function() {return {sayHello: function() {return "Hello, World!";}};});    
//provider style, full blown, configurable versionmyApp.provider('helloWorld', function() {
this.name = 'Default';
this.$get = function() {var name = this.name;return {sayHello: function() {return "Hello, " + name + "!";}}};
this.setName = function(name) {this.name = name;};});
//hey, we can configure a provider!myApp.config(function(helloWorldProvider){helloWorldProvider.setName('World');});        

function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {    
$scope.hellos = [helloWorld.sayHello(),helloWorldFromFactory.sayHello(),helloWorldFromService.sayHello()];}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script><body ng-app="myApp"><div ng-controller="MyCtrl">\{\{hellos}}</div></body>

所有服务都是单例;它们每个应用程序实例化一次。它们可以是任何类型,无论是原始、对象文字、函数,甚至是自定义类型的实例。

valuefactoryserviceconstantprovider方法都是提供者。它们教注入器如何实例化服务。

最冗长,但也是最全面的一个是提供者配方。其余四配方类型-值、工厂、服务和常量-只是提供者配方上的语法糖.

  • 超值配方是最简单的情况,您自己实例化服务并将实例化值提供给注入器。
  • 工厂配方为注入器提供了一个工厂函数,它在需要实例化服务时调用该函数。调用时,工厂函数创建并返回服务实例。服务的依赖项作为函数的参数注入。因此使用此配方添加了以下功能:
    • 能够使用其他服务(有依赖关系)
    • 服务初始化
    • 延迟/懒惰初始化
  • 服务配方与工厂配方几乎相同,但这里注入器使用new运算符而不是工厂函数调用构造函数
  • 提供者配方通常是过度杀伤。它通过允许您配置工厂的创建来增加一层间接。

    只有当您想公开API时,才应该使用Provider配方对于应用程序范围的配置,必须在应用程序启动。这通常只对可重用感兴趣服务,其行为可能需要在应用程序。

  • 不断的食谱就像价值配方一样,只是它允许您定义在配置阶段可用的服务。比使用价值配方创建的服务更快。与值不同,它们不能使用decorator进行装饰。
提供者留档.

对我来说,理解差异的最好和最简单的方法是:

var service, factory;service = factory = function(injection) {}

AngularJS如何实例化特定组件(简化):

// servicevar angularService = new service(injection);
// factoryvar angularFactory = factory(injection);

因此,对于服务,成为AngularJS组件的是由服务声明函数表示的类的对象实例。对于工厂,它是工厂声明函数返回的结果。工厂的行为可能与服务相同:

var factoryAsService = function(injection) {return new function(injection) {// Service content}}

最简单的思考方式如下:

  • 服务是单例对象实例。如果要为代码提供单例对象,请使用服务。
  • 工厂是一个类。如果您想为您的代码提供自定义类,请使用工厂(不能使用服务完成,因为它们已经实例化)。

工厂'类'示例在注释中提供,以及提供者的区别。

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

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

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)当你使用工厂时,你创建一个对象,向其添加属性,然后返回同一个对象。当您将此工厂传递给您的控制器时,对象上的这些属性现在将通过您的工厂在该控制器中可用。

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)当你使用服务时,AngularJS会在幕后使用new关键字实例化它。因此,你将向this添加属性,服务将返回this。当你将服务传递给你的控制器时,this上的那些属性现在将通过你的服务在该控制器上可用。

app.controller(‘myServiceCtrl’, function($scope, myService){$scope.artist = myService.getArtist();});
app.service(‘myService’, function(){var _artist = ‘Nelly’;this.getArtist = function(){return _artist;}});



3)提供商是您可以传递给. config()函数的唯一服务。如果您想在服务对象可用之前为其提供模块范围的配置,请使用提供者。

app.controller(‘myProvider’, function($scope, myProvider){$scope.artist = myProvider.getArtist();$scope.data.thingFromConfig = myProvider.thingOnConfig;});
app.provider(‘myProvider’, function(){//Only the next two lines are available in the app.config()this._artist = ‘’;this.thingFromConfig = ‘’;this.$get = function(){var that = this;return {getArtist: function(){return that._artist;},thingOnConfig: that.thingFromConfig}}});
app.config(function(myProviderProvider){myProviderProvider.thingFromConfig = ‘This was set in config’;});



太长别读

1)工厂
工厂是创建和配置服务的最流行的方式。没有什么比太长别读说的更多的了。你只需创建一个对象,向其添加属性,然后返回相同的对象。然后当你将工厂传递给你的控制器时,对象上的这些属性现在将通过你的工厂在该控制器中可用。下面是一个更广泛的例子。

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

现在,当我们将“myFactory”传递给我们的控制器时,我们附加到“service”的任何属性都将可用。

现在让我们在回调函数中添加一些“私有”变量。这些变量不能从控制器直接访问,但我们最终会在“service”上设置一些getter/setter方法,以便能够在需要时更改这些“私有”变量。

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

在这里,您会注意到我们没有将这些变量/函数附加到“service”。我们只是创建它们以便以后使用或修改它们。

  • BaseUrl是iTunesAPI需要的基本URL
  • _artist就是我们要找的艺术家
  • _finalUrl是我们将调用iTunes的最终且完全构建的URL
  • makeUrl是一个函数,它将创建并返回我们iTunes友好的URL。

现在我们的辅助/私有变量和函数已经就位,让我们向“service”对象添加一些属性。我们放在“service”上的任何内容都可以直接在我们传递“myFactory”到的任何控制器中使用。

我们将创建setArtist和getArtist方法来简单地返回或设置艺术家。我们还将创建一个使用我们创建的URL调用iTunesAPI的方法。这个方法将返回一个Promise,一旦数据从iTunesAPI返回就会实现。如果你在AngularJS中没有太多使用Promise的经验,我强烈建议你深入研究它们。

下面setArtist接受一个艺术家并允许你设置艺术家。获取艺人返回艺术家。调用列表首先调用makeUrl()以构建我们将用于我们的$超文本传输协议请求的URL。然后它设置了一个Promise对象,用我们的最终URL发出$超文本传输协议请求,然后因为$超文本传输协议返回了Promise,我们可以在请求后调用.成功或. error。然后我们用iTunes数据解析我们的Promise,或者我们用一条消息说'有一个错误'拒绝它。

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

现在我们的工厂完成了。我们现在可以将'myFactory'注入任何控制器,然后我们将能够调用我们附加到服务对象的方法(setArtist、getArtist和call Itune es)。

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

在上面的控制器中,我们注入了'myFactory'服务。然后我们使用来自'myFactory'的数据在我们的$范围对象上设置属性。上面唯一棘手的代码是如果你以前从未处理过Promise。因为call Itune es返回的是一个Promise,所以我们能够使用. thi()方法并且只有在iTunes数据实现我们的Promise后才设置$scope.data.artistData。你会注意到我们的控制器非常'薄'(这是一个很好的编码实践)。我们所有的逻辑和持久数据都位于我们的服务中,而不是我们的控制器中。

2)服务
也许在创建服务时最重要的一点是它是使用“new”关键字实例化的。对于JavaScript大师来说,这应该会让你对代码的本质有一个很大的提示。对于那些JavaScript背景有限的人,或者那些不太熟悉“new”关键字实际作用的人,让我们回顾一些JavaScript基础知识,这些基础知识最终将帮助我们理解服务的本质。

要真正看到使用new关键字调用函数时发生的变化,让我们创建一个函数并使用new关键字调用它,然后让我们展示解释器在看到new关键字时所做的事情。最终结果将是相同的。

首先,创建我们的Constructor。

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

这是一个典型的JavaScript构造函数。现在,每当我们使用'new'关键字调用Person函数时,'this'将绑定到新创建的对象。

现在让我们在Person的原型上添加一个方法,这样它就可以在Person'class'的每个实例上使用。

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

现在,因为我们将sayName函数放在原型上,所以Person的每个实例都可以调用sayName函数以提醒该实例的名称。

现在我们在其原型上有了Person构造函数和sayName函数,让我们实际创建一个Person的实例,然后调用sayName函数。

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

因此,创建Person构造函数,向其原型添加函数,创建Person实例,然后在其原型上调用该函数的所有代码看起来像这样。

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’

现在让我们看看当你在JavaScript中使用'new'关键字时实际发生了什么。你应该注意到的第一件事是,在我们的示例中使用'new'之后,我们可以调用'tyler'上的方法(sayName),就像它是一个对象一样-这是因为它是。因此,首先,我们知道我们的Person构造函数正在返回一个对象,无论我们是否可以在代码中看到它。其次,我们知道因为我们的sayName函数位于原型上而不是直接位于Person实例上,所以Person函数返回的对象必须在查找失败时委托给其原型。更简单地说,当我们调用tyler.sayName()时,解释器说“好的,我要查看我们刚刚创建的'tyler'对象,找到sayName函数,然后调用它。等一下,我在这里看不到它-我看到的只是名称和年龄,让我检查一下原型。是的,看起来它的原型,让我叫它。”.

下面是如何思考'new'关键字在JavaScript中的实际作用的代码。它基本上是上面段落的代码示例。我把'解释器视图'或解释器看到代码的方式放在注释中。

var Person = function(name, age){//The below line creates an object(obj) 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;}

现在了解了“new”关键字在JavaScript中的真正作用,在AngularJS中创建服务应该更容易理解。

创建服务时要了解的最重要的事情是知道服务是用'new'关键字实例化的。将这些知识与上面的示例结合起来,你现在应该认识到你将直接将属性和方法附加到'this',然后这些属性和方法将从服务本身返回。让我们看看实际情况。

与我们最初使用Factory示例所做的不同,我们不需要创建一个对象然后返回该对象,因为就像之前多次提到的那样,我们使用了'new'关键字,因此解释器将创建该对象,将其委托给它的原型,然后为我们返回它,而无需我们做这项工作。

首先,让我们创建我们的'Private'和helper函数。这应该看起来很熟悉,因为我们对工厂做了完全相同的事情。我不会在这里解释每一行的作用,因为我在工厂示例中做了这件事,如果你感到困惑,请重新阅读工厂示例。

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'。

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

现在就像在我们的工厂中一样,setArtist、getArtist和call Itune es将在我们将myService传递到的任何控制器中可用。这是myService控制器(它几乎与我们的工厂控制器完全相同)。

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

就像我之前提到的,一旦你真正理解了什么是“新”,服务几乎与AngularJS中的工厂相同。

3)提供者

关于Providers需要记住的最重要的一点是,它们是您可以传递到应用程序app.config部分的唯一服务。如果您需要在服务对象的某些部分在应用程序的其他地方可用之前更改它,这一点非常重要。虽然与服务/工厂非常相似,但我们将讨论一些差异。

首先,我们以与服务和工厂类似的方式设置提供者。下面的变量是我们的“私有”和辅助函数。

app.provider('myProvider', function(){var baseUrl = 'https://itunes.apple.com/search?term=';var _artist = '';var _finalUrl = '';
//Going to set this property on the config function below.this.thingFromConfig = ‘’;
var makeUrl = function(){_artist = _artist.split(' ').join('+');_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'return _finalUrl;}}

*如果上述代码的任何部分令人困惑,请查看工厂部分,其中我解释了这一切的更多细节。

您可以将Providers视为包含三个部分。第一部分是稍后将被修改/设置的“私有”变量/函数(如上所示)。第二部分是在您的app.config函数中可用的变量/函数,因此可以在其他任何地方可用之前进行更改(如上所示)。重要的是要注意这些变量需要附加到“this”关键字。在我们的示例中,只有“thingFromConfig”可以在app.config.中进行更改。第三部分(如下所示)是当您将“myProvider”服务传入特定控制器时,控制器中可用的所有变量/函数。

当使用Provider创建服务时,控制器中唯一可用的属性/方法是从$get()函数返回的属性/方法。下面的代码将$get放在'this'上(我们知道它最终会从该函数返回)。现在,$get函数返回我们希望在控制器中可用的所有方法/属性。这是一个代码示例。

this.$get = function($http, $q){return {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;},setArtist: function(artist){_artist = artist;},getArtist: function(){return _artist;},thingOnConfig: this.thingFromConfig}}

完整的Provider代码如下所示

app.provider('myProvider', function(){var baseUrl = 'https://itunes.apple.com/search?term=';var _artist = '';var _finalUrl = '';
//Going to set this property on the config function belowthis.thingFromConfig = '';
var makeUrl = function(){_artist = _artist.split(' ').join('+');_finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'return _finalUrl;}
this.$get = function($http, $q){return {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;},setArtist: function(artist){_artist = artist;},getArtist: function(){return _artist;},thingOnConfig: this.thingFromConfig}}});

现在就像在我们的工厂和服务中一样,无论我们将myProvider传递到哪个控制器中,setArtist、getArtist和call Itune es都将可用。这是myProvider控制器(它几乎与我们的工厂/服务控制器完全相同)。

app.controller('myProviderCtrl', function($scope, myProvider){$scope.data = {};$scope.updateArtist = function(){myProvider.setArtist($scope.data.artist);};
$scope.submitArtist = function(){myProvider.callItunes().then(function(data){$scope.data.artistData = data;}, function(data){alert(data);})}
$scope.data.thingFromConfig = myProvider.thingOnConfig;});

如前所述,使用Provider创建服务的全部意义在于能够在最终对象传递给应用程序的其余部分之前通过app.config函数更改一些变量。

app.config(function(myProviderProvider){//Providers are the only service you can pass into app.configmyProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works';});

现在您可以看到'thingFromConfig'在我们的提供程序中是如何作为空字符串的,但是当它出现在DOM中时,它将是'这句话被设置…'。

下面我的理解很简单。

<强>工厂:您只需在工厂内部创建一个对象并返回它。

服务:

您只有一个标准函数,它使用这个关键字来定义一个函数。

提供者:

您定义了一个$get对象,它可用于获取返回数据的对象。

服务vs供应商vs工厂:

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

首先,让我们谈谈AngularJS中的服务

什么是服务:在AngularJS中,服务只不过是一个单例JavaScript对象,它可以存储一些有用的方法或属性。这个单例对象是基于每个ngApp(Angular app)创建的,它在当前应用程序中的所有控制器之间共享。当Angularjs实例化一个服务对象时,它会用一个唯一的服务名称注册这个服务对象。所以每次我们需要服务实例时,Angular在注册表中搜索这个服务名称,它会返回对服务对象的引用。这样我们就可以调用服务对象的方法、访问属性等。为什么需要服务对象?答案是:服务在多个控制器范围之间共享。如果你把一些属性/方法放在控制器的范围对象中,它将仅对当前范围可用。但是当你在服务对象上定义方法、属性时,它将在全局可用,并且可以通过注入该服务在任何控制器的范围内访问。

因此,如果有三个控制器作用域,则设为控制器A、控制器B和控制器C,它们都将共享相同的服务实例。

<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提供了服务名称工厂名称方法,它接受两个参数,serviceName和一个JavaScript函数。Angular通过调用函数fnFactory创建服务实例,如下所示。

var serviceInstace = fnFactory();

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

示例:

var app= angular.module('myApp', []);//creating service using factory methodapp.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 objectreturn data;});

服务功能:

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

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

var serviceInstance = new fnServiceConstructor();

在构造函数中,我们可以使用'this'关键字向服务对象添加属性/方法。示例:

//Creating a service using the service methodvar 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将其提供给创建我们服务实例的工厂/构造函数。在这种情况下,提供者()函数完成工作。使用提供者()函数,我们可以创建可配置的服务。

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

/*step1:define a service */app.provider('service',function serviceProviderConstructor(){});
/*step2:configure the service */app.config(function configureService(serviceProvider){});

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

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

var serviceProvider = new serviceProviderConstructor();

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

configureService(serviceProvider);

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

serviceInstance = serviceProvider.$get()

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

var app= angular.module('myApp', []);app.provider('providerPattern',function providerConstructor(){//this function works as constructor function for providerthis.firstName = 'Arnold ';this.lastName = ' Schwarzenegger' ;this.greetMessage = ' Welcome, This is default Greeting Message' ;//adding some method which we can call in app.config() functionthis.setGreetMsg = function(msg){if(msg){this.greetMessage =  msg ;}};
//We can also add a method which can change firstName and lastNamethis.$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=new fnServiceConstructor();/服务实例

提供商定义了一个提供者构造函数,这个提供者构造函数定义了一个工厂函数$获取。Angular调用$get()来创建服务对象。提供者语法还有一个额外的优势,即在服务对象实例化之前配置它。服务实例=$get();

工厂

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

示例:

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

用法:

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

服务

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

示例:

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

对我来说,当我意识到它们都以相同的方式工作时,启示就来了:通过运行一次,存储它们获得的值,然后在通过依赖注入引用时咳嗽相同的存储值

假设我们有:

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

三者的区别在于:

  1. a的存储值来自运行fn
  2. b的存储值来自newingfn
  3. c的存储值来自于首先通过new ingfn获取一个实例,然后运行该实例的$get方法。

这意味着AngularJS中有一个类似缓存对象的东西,每次注入的值只分配一次,当它们第一次注入时,在哪里:

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

这就是为什么我们在服务中使用this,并在提供商中定义this.$get

我对此事的澄清:

基本上所有提到的类型(服务、工厂、提供者等)都只是创建和配置全局变量(当然对整个应用程序来说是全局的),就像老式的全局变量一样。

虽然不建议使用全局变量,但这些全局变量的实际用法是通过将变量传递给相关控制器来提供依赖注入

创建“全局变量”的值有许多复杂的层次:

  1. 恒定
    这定义了一个在整个应用程序中不应该修改的实际常量,就像其他语言中的常量一样(JavaScript缺乏的东西)。

  2. 这是一个可修改的值或对象,它充当一些全局变量,甚至可以在创建其他服务或工厂时注入(详见这些)。但是,它必须是“文字值”,这意味着必须写出实际值,并且不能使用任何计算或编程逻辑(换句话说,39myText可以,但2+2不行)。
  3. 工厂
    一个更通用的值,可以立即计算。它的工作原理是将一个函数传递给AngularJS,其中包含计算该值所需的逻辑,AngularJS执行它,并将返回值保存在命名变量中。
    请注意,可以返回一个对象(在这种情况下,它的功能类似于服务)或一个函数(将作为回调函数保存在变量中)。
  4. 服务
    服务是工厂的简化版本,只有当值是对象时才有效,它允许直接在函数中编写任何逻辑(就好像它是构造函数一样),以及使用这个关键字声明和访问对象属性。
  5. 提供商
    工厂的简化版本的服务不同,提供者是一种更复杂但更灵活的初始化“全局”变量的方式,最大的灵活性是可以选择从app.config.
    设置值它的工作原理类似于使用服务提供商的组合,通过向提供者传递一个函数,该函数具有使用这个关键字声明的属性,可以从app.config使用。
    然后它需要有一个单独的$. get函数,在通过app.config文件设置上述属性后由AngularJS执行,这个$. get函数的行为与上面的工厂相同,因为它的返回值用于初始化“全局”变量。

使用此页面和留档作为参考(自上次查看以来似乎有了很大的改进),我将以下真实(-ish)世界演示放在一起,其中使用了5种提供者中的4种;价值,常量,工厂和成熟的提供者。

超文本标记语言:

<div ng-controller="mainCtrl as main"><h1>\{\{main.title}}*</h1><h2>\{\{main.strapline}}</h2><p>Earn \{\{main.earn}} per click</p><p>You've earned \{\{main.earned}} by clicking!</p><button ng-click="main.handleClick()">Click me to earn</button><small>* Not actual money</small></div>

应用程序

var app = angular.module('angularProviders', []);
// A CONSTANT is not going to changeapp.constant('range', 100);
// A VALUE could change, but probably / typically doesn'tapp.value('title', 'Earn money by clicking');app.value('strapline', 'Adventures in ng Providers');
// A simple FACTORY allows us to compute a value @ runtime.// Furthermore, it can have other dependencies injected into it such// as our range constant.app.factory('random', function randomFactory(range) {// Get a random number within the range defined in our CONSTANTreturn Math.random() * range;});
// A PROVIDER, must return a custom type which implements the functionality// provided by our service (see what I did there?).// Here we define the constructor for the custom type the PROVIDER below will// instantiate and return.var Money = function(locale) {
// Depending on locale string set during config phase, we'll// use different symbols and positioning for any values we// need to display as currencythis.settings = {uk: {front: true,currency: '£',thousand: ',',decimal: '.'},eu: {front: false,currency: '€',thousand: '.',decimal: ','}};
this.locale = locale;};
// Return a monetary value with currency symbol and placement, and decimal// and thousand delimiters according to the locale set in the config phase.Money.prototype.convertValue = function(value) {
var settings = this.settings[this.locale],decimalIndex, converted;
converted = this.addThousandSeparator(value.toFixed(2), settings.thousand);
decimalIndex = converted.length - 3;
converted = converted.substr(0, decimalIndex) +settings.decimal +converted.substr(decimalIndex + 1);
converted = settings.front ?settings.currency + converted :converted + settings.currency;
return converted;};
// Add supplied thousand separator to supplied valueMoney.prototype.addThousandSeparator = function(value, symbol) {return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, symbol);};
// PROVIDER is the core recipe type - VALUE, CONSTANT, SERVICE & FACTORY// are all effectively syntactic sugar built on top of the PROVIDER construct// One of the advantages of the PROVIDER is that we can configure it before the// application starts (see config below).app.provider('money', function MoneyProvider() {
var locale;
// Function called by the config to set up the providerthis.setLocale = function(value) {locale = value;};
// All providers need to implement a $get method which returns// an instance of the custom class which constitutes the servicethis.$get = function moneyFactory() {return new Money(locale);};});
// We can configure a PROVIDER on application initialisation.app.config(['moneyProvider', function(moneyProvider) {moneyProvider.setLocale('uk');//moneyProvider.setLocale('eu');}]);
// The ubiquitous controllerapp.controller('mainCtrl', function($scope, title, strapline, random, money) {
// Plain old VALUE(s)this.title = title;this.strapline = strapline;
this.count = 0;
// Compute values using our money providerthis.earn = money.convertValue(random); // random is computed @ runtimethis.earned = money.convertValue(0);
this.handleClick = function() {this.count ++;this.earned = money.convertValue(random * this.count);};});

工作demo

了解AngularJS工厂、服务和提供商

所有这些都用于共享可重用的单例对象。它有助于在您的应用程序/各种组件/模块之间共享可重用代码。

从文档服务/工厂

  • 懒惰实例化-Angular仅在应用程序组件依赖它时实例化服务/工厂。
  • Singletons-每个组件依赖于服务获取对单个实例的引用由服务工厂生成。

工厂

工厂是一个函数,您可以在创建对象之前操作/添加逻辑,然后返回新创建的对象。

app.factory('MyFactory', function() {var serviceObj = {};//creating an object with methods/functions or variablesserviceObj.myFunction = function() {//TO DO:};//return that objectreturn serviceObj;});

用法

它可以只是像类一样的函数集合。因此,当你在控制器/工厂/指令函数中注入它时,它可以在不同的控制器中实例化。每个应用程序只实例化一次。

服务

简单地在查看服务时考虑数组原型。服务是使用new关键字实例化新对象的函数。您可以使用this关键字向服务对象添加属性和函数。与工厂不同,它不返回任何东西(它返回一个包含方法/属性的对象)。

app.service('MyService', function() {//directly binding events to this contextthis.myServiceFunction = function() {//TO DO:};});

用法

当您需要在整个应用程序中共享单个对象时使用它。例如,经过身份验证的用户详细信息、可共享的方法/数据、实用程序函数等。

提供商

提供者用于创建可配置的服务对象。您可以从config函数配置服务设置。它使用$get()函数返回一个值。$get函数在运行阶段以角度执行。

app.provider('configurableService', function() {var name = '';//this method can be be available at configuration time inside app.config.this.setName = function(newName) {name = newName;};this.$get = function() {var getName = function() {return name;};return {getName: getName //exposed object to where it gets injected.};};});

用法

当您需要在服务对象可用之前为其提供模块配置时,例如。假设您想根据您的环境设置API URL,例如devstageprod

只有提供者将在角度的配置阶段可用,而服务和工厂不是。

希望这能澄清你对工厂,服务和供应商的理解。

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

这是我在AngularjS中作为对象工厂的代码模板想出来的一些样板代码。我使用Car/CarFactory作为示例来说明。在控制器中制作简单的实现代码。

     <script>angular.module('app', []).factory('CarFactory', function() {
/*** BroilerPlate Object Instance Factory Definition / Example*/this.Car = function() {
// initialize instance propertiesangular.extend(this, {color           : null,numberOfDoors   : null,hasFancyRadio   : null,hasLeatherSeats : null});
// generic setter (with optional default value)this.set = function(key, value, defaultValue, allowUndefined) {
// by default,if (typeof allowUndefined === 'undefined') {// we don't allow setter to accept "undefined" as a valueallowUndefined = false;}// if we do not allow undefined values, and..if (!allowUndefined) {// if an undefined value was passed inif (value === undefined) {// and a default value was specifiedif (defaultValue !== undefined) {// use the specified default valuevalue = defaultValue;} else {// otherwise use the class.prototype.defaults valuevalue = this.defaults[key];} // end if/else} // end if} // end if
// updatethis[key] = value;
// return reference to this object (fluent)return this;
}; // end this.set()
}; // end this.Car class definition
// instance properties default valuesthis.Car.prototype.defaults = {color: 'yellow',numberOfDoors: 2,hasLeatherSeats: null,hasFancyRadio: false};
// instance factory method / constructorthis.Car.prototype.instance = function(params) {return newthis.constructor().set('color',           params.color).set('numberOfDoors',   params.numberOfDoors).set('hasFancyRadio',   params.hasFancyRadio).set('hasLeatherSeats', params.hasLeatherSeats);};
return new this.Car();
}) // end Factory Definition.controller('testCtrl', function($scope, CarFactory) {
window.testCtrl = $scope;
// first car, is red, uses class default for:// numberOfDoors, and hasLeatherSeats$scope.car1     = CarFactory.instance({color: 'red'});
// second car, is blue, has 3 doors,// uses class default for hasLeatherSeats$scope.car2     = CarFactory.instance({color: 'blue',numberOfDoors: 3});// third car, has 4 doors, uses class default for// color and hasLeatherSeats$scope.car3     = CarFactory.instance({numberOfDoors: 4});// sets an undefined variable for 'hasFancyRadio',// explicitly defines "true" as default when value is undefined$scope.hasFancyRadio = undefined;$scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);
// fourth car, purple, 4 doors,// uses class default for hasLeatherSeats$scope.car4     = CarFactory.instance({color: 'purple',numberOfDoors: 4});// and then explicitly sets hasLeatherSeats to undefined$scope.hasLeatherSeats = undefined;$scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);
// in console, type window.testCtrl to see the resulting objects
});</script>

这是一个更简单的例子。我正在使用一些第三方库,它们期望“位置”对象暴露纬度和经度,但通过不同的对象属性。我不想破解供应商代码,所以我调整了我传递的“位置”对象。

    angular.module('app').factory('PositionFactory', function() {
/*** BroilerPlate Object Instance Factory Definition / Example*/this.Position = function() {
// initialize instance properties// (multiple properties to satisfy multiple external interface contracts)angular.extend(this, {lat         : null,lon         : null,latitude    : null,longitude   : null,coords: {latitude: null,longitude: null}});
this.setLatitude = function(latitude) {this.latitude           = latitude;this.lat                = latitude;this.coords.latitude    = latitude;return this;};this.setLongitude = function(longitude) {this.longitude          = longitude;this.lon                = longitude;this.coords.longitude   = longitude;return this;};
}; // end class definition
// instance factory method / constructorthis.Position.prototype.instance = function(params) {return newthis.constructor().setLatitude(params.latitude).setLongitude(params.longitude);};
return new this.Position();
}) // end Factory Definition
.controller('testCtrl', function($scope, PositionFactory) {$scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});$scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});}) // end controller

我知道很多优秀的答案,但我必须分享我的使用经验
1.service对于大多数默认情况
2.factory用于创建特定实例的服务

// 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' modelvar books = new xFactory({'model': 'book', 'mode': 'list'});
// accounts = new instance of xFactory for query 'accounts' modelvar accounts = new xFactory({'model': 'account', 'mode': 'list'});
// accounts2 = accounts variablevar accounts2 = xService;...

这个答案涉及主题/问题

工厂,服务和常量-只是提供商配方之上的语法糖?

工厂、服务和供应商如何在内部解决问题

基本上发生的事情是

当您创建factory()时,它会将您在第二个参数中提供的function设置为提供者的$get并返回它(provider(name, {$get:factoryFn })),provider中的你得到的是#4,但除了#2之外没有其他属性/方法(意味着您无法配置它)

工厂源代码

function factory(name, factoryFn, enforce) {return provider(name, {$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn});};

当创建service()时,它返回您提供一个带有function的工厂(),该工厂注入constructor(返回您在服务中提供的构造函数的实例)并返回它

服务源代码

function service(name, constructor) {return factory(name, ['$injector', function($injector) {return $injector.instantiate(constructor);}]);};

因此,基本上在这两种情况下,您最终都会获得提供者$get设置为您提供的函数,但您可以提供除$get之外的任何内容,因为您最初可以在提供者()中为配置块提供

已经有了很好的答案,但我只想分享这个。

首先:提供商是创建service(单例对象)的方法/配方,该方法假设由$injector注入(AngulaJS如何处理IoC模式)。

价值、工厂、服务与常量(4种方式)-语法糖超过提供商种方式/接受。

Service vs Factory部分已被覆盖:https://www.youtube.com/watch?v=BLzNCkPn3ao

服务实际上是关于new关键字的,正如我们所知,它做了4件事:

  1. 创建全新的对象
  2. 将其链接到其prototype对象
  3. 连接contextthis
  4. 并返回this

工厂是关于工厂模式的-包含返回类似于该服务的对象的函数。

  1. 能够使用其他服务(有依赖关系)
  2. 服务初始化
  3. 延迟/延迟初始化

这个简单/简短的视频也涵盖了提供商https://www.youtube.com/watch?v=HvTZbQ_hUZY(在那里你可以看到他们如何从工厂到供应商)

提供商配方主要在应用程序配置中使用,在应用程序完全启动/初始化之前。

这是非常混乱的部分为新手和我试图澄清它在简单的话

AngularJS服务:用于与控制器中的服务引用共享实用程序功能。服务本质上是单例的,因此对于一项服务,在浏览器中只创建一个实例,并且在整个页面中使用相同的引用。

在服务中,我们使用这个对象创建函数名称作为属性。

AngularJS工厂:工厂的目的也与服务相同,但在这种情况下,我们创建一个新对象并添加函数作为该对象的属性,最后我们返回该对象。

AngularJS提供者:的目的也是一样的,但是Provider给出了它的$get函数的输出。

定义和使用服务,工厂和提供商在http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider中解释

正如这里的几个人正确指出的那样,工厂、提供商、服务,甚至价值和常量都是同一事物的版本。您可以将更通用的provider分解为所有这些。如下所示:

在此处输入图片描述

这是这张图片来自的文章:

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

有点晚了。但我认为这对那些想学习(或清楚)使用工厂、服务和提供者方法开发Angular JS Custom Services的人更有帮助。

我看到了这个视频,它清楚地解释了开发AngularJS自定义服务的工厂、服务和提供者方法:

https://www.youtube.com/watch?v=oUXku28ex-M

源代码:http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service

此处发布的代码直接从上述来源复制,以使读者受益。

基于“工厂”的自定义服务的代码如下(同步和异步版本以及调用超文本传输协议服务):

var app = angular.module("app", []);app.controller('emp', ['$scope', 'calcFactory',function($scope, calcFactory) {$scope.a = 10;$scope.b = 20;
$scope.doSum = function() {//$scope.sum = calcFactory.getSum($scope.a, $scope.b); //synchronouscalcFactory.getSum($scope.a, $scope.b, function(r) { //aynchronous$scope.sum = r;});};
}]);
app.factory('calcFactory', ['$http', '$log',function($http, $log) {$log.log("instantiating calcFactory..");var oCalcService = {};
//oCalcService.getSum = function(a,b){//	return parseInt(a) + parseInt(b);//};
//oCalcService.getSum = function(a, b, cb){//	var s = parseInt(a) + parseInt(b);//	cb(s);//};
oCalcService.getSum = function(a, b, cb) { //using http service
$http({url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,method: 'GET'}).then(function(resp) {$log.log(resp.data);cb(resp.data);}, function(resp) {$log.error("ERROR occurred");});};
return oCalcService;}]);

自定义服务的“service”方法论代码(这与“工厂”非常相似,但从语法角度来看有所不同):

var app = angular.module("app", []);app.controller('emp', ['$scope', 'calcService', function($scope, calcService){$scope.a = 10;$scope.b = 20;
$scope.doSum = function(){//$scope.sum = calcService.getSum($scope.a, $scope.b);		
calcService.getSum($scope.a, $scope.b, function(r){$scope.sum = r;});};
}]);
app.service('calcService', ['$http', '$log', function($http, $log){$log.log("instantiating calcService..");	
//this.getSum = function(a,b){//	return parseInt(a) + parseInt(b);//};
//this.getSum = function(a, b, cb){//	var s = parseInt(a) + parseInt(b);//	cb(s);//};
this.getSum = function(a, b, cb){$http({url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,method: 'GET'}).then(function(resp){$log.log(resp.data);cb(resp.data);},function(resp){$log.error("ERROR occurred");});};
}]);

自定义服务的“提供者”方法论代码(如果您想开发可以配置的服务,这是必要的):

var app = angular.module("app", []);app.controller('emp', ['$scope', 'calcService', function($scope, calcService){$scope.a = 10;$scope.b = 20;
$scope.doSum = function(){//$scope.sum = calcService.getSum($scope.a, $scope.b);		
calcService.getSum($scope.a, $scope.b, function(r){$scope.sum = r;});};
}]);
app.provider('calcService', function(){
var baseUrl = '';
this.config = function(url){baseUrl = url;};
this.$get = ['$log', '$http', function($log, $http){$log.log("instantiating calcService...")var oCalcService = {};
//oCalcService.getSum = function(a,b){//	return parseInt(a) + parseInt(b);//};
//oCalcService.getSum = function(a, b, cb){//	var s = parseInt(a) + parseInt(b);//	cb(s);//};
oCalcService.getSum = function(a, b, cb){
$http({url: baseUrl + '/Sum?a=' + a + '&b=' + b,method: 'GET'}).then(function(resp){$log.log(resp.data);cb(resp.data);},function(resp){$log.error("ERROR occurred");});};
return oCalcService;}];
});
app.config(['calcServiceProvider', function(calcServiceProvider){calcServiceProvider.config("http://localhost:4467");}]);

最后是与上述任何服务一起工作的UI:

<html><head><title></title><script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js" ></script><script type="text/javascript" src="t03.js"></script></head><body ng-app="app"><div ng-controller="emp"><div>Value of a is \{\{a}},but you can change<input type=text ng-model="a" /> <br>
Value of b is \{\{b}},but you can change<input type=text ng-model="b" /> <br>
</div>Sum = \{\{sum}}<br><button ng-click="doSum()">Calculate</button></div></body></html>

只是为了澄清一些事情,从AngularJS源代码中,你可以看到一个服务只是调用工厂函数,而工厂函数又调用提供者函数:

function factory(name, factoryFn) {return provider(name, { $get: factoryFn });}
function service(name, constructor) {return factory(name, ['$injector', function($injector) {return $injector.instantiate(constructor);}]);}

语法糖是区别。只需要提供者。或者换句话说,只有提供者才是真正的角度,所有其他的都是派生的(以减少代码)。还有一个简单的版本,称为Value(),它只返回值,没有计算或函数。甚至Value也是从提供者派生的!

那么,为什么会出现这样的复杂情况呢?为什么我们不能只使用提供者而忘记其他一切呢?它应该帮助我们轻松编写代码并更好地沟通。而开玩笑的回答是,它变得越复杂,销售框架就越好。


  • 一个可以返回value=Value的提供者
  • 一个提供者可以实例化并返回=Factory(+Value)
  • 一个可以实例化+做某事=服务(+工厂,+价值)
  • 提供者=必须包含一个名为$get(+Factory,+Service,+Value)的属性

角注入给了我们得出这个结论的第一个提示。

“$injector用于检索提供商定义的对象实例”不是服务,不是工厂,而是提供者。

更好的答案是:"Angular服务由服务工厂创建。这些服务工厂是由服务提供者创建的函数。服务提供者是构造函数。实例化时,它们必须包含一个名为$get的属性,该属性保存服务工厂函数。"

所以主提供者和注入器以及所有这些都将到位:)。当$get可以通过从IServiceProvider继承在提供者中实现时,在TypeScript中变得有趣。

总结Angular文档

  • 有五种配方类型定义了如何创建对象:工厂服务提供者常量
  • 工厂服务是最常用的配方。它们之间唯一的区别是服务配方更适合自定义类型的对象,而工厂可以生成JavaScript原语和函数。
  • 提供商配方是核心配方类型,所有其他的只是语法糖。
  • 提供商是最复杂的配方类型。除非您正在构建需要全局配置的可重用代码段,否则您不需要它。

在此处输入图片描述


最佳答案:

https://stackoverflow.com/a/26924234/165673(<--好)https://stackoverflow.com/a/27263882/165673
https://stackoverflow.com/a/16566144/165673

1.服务是在必要时创建的单例对象,在应用程序生命周期结束(浏览器关闭时)之前永远不会清理。控制器在不再需要时被销毁和清理。

2.创建服务的最简单方法是使用工厂()方法。工厂()方法允许我们通过返回一个包含服务函数和服务数据的对象来定义服务。服务定义函数是我们放置可注入服务的地方,例如$超文本传输协议和$q。例如:

angular.module('myApp.services').factory('User', function($http) { // injectables go herevar backendUrl = "http://localhost:3000"; var service = {// our factory definitionuser: {},setName: function(newName) {service.user['name'] = newName;},setEmail: function(newEmail) { service.user['email'] = newEmail;},save: function() {return $http.post(backendUrl + '/users', { user: service.user}); }};return service; });

在我们的应用程序中使用工厂()

在我们的应用程序中使用工厂很容易,因为我们可以简单地在运行时将其注入我们需要的地方。

angular.module('myApp').controller('MainController', function($scope, User) {$scope.saveUser = User.save;});
  1. 另一方面,service()方法允许我们通过定义构造函数来创建服务。我们可以使用原型对象来定义我们的服务,而不是原始的javascript对象。与工厂()方法类似,我们也将在函数定义中设置注入。
  2. 创建服务的最低级别方法是使用提供()方法。这是创建我们可以使用. config()函数配置的服务的唯一方法。与前面的to方法不同,我们将在定义的this.$get()函数定义中设置注入。

让我们以简单的方式讨论在AngularJS中处理业务逻辑的三种方法:(受Yaakov的Coursera AngularJS课程启发

服务

语法:

app.js

 var app = angular.module('ServiceExample',[]);var serviceExampleController =app.controller('ServiceExampleController', ServiceExampleController);var serviceExample = app.service('NameOfTheService', NameOfTheService);
ServiceExampleController.$inject = ['NameOfTheService'] //protects from minification of js files
function ServiceExampleController(NameOfTheService){serviceExampleController = this;serviceExampleController.data = NameOfTheService.getSomeData();}
function NameOfTheService(){nameOfTheService = this;nameOfTheService.data = "Some Data";nameOfTheService.getSomeData = function(){return nameOfTheService.data;}}

index.html

<div ng-controller = "ServiceExampleController as serviceExample">\{\{serviceExample.data}}</div>

服务特点:

  1. 懒惰实例化:如果没有注入,它永远不会被实例化。所以要使用它,必须将其注入到模块中。
  2. Singleton:如果注入到多个模块,所有模块都只能访问一个特定的实例。这就是为什么在不同控制器之间共享数据非常方便。

工厂

首先我们来看看语法:

app.js

var app = angular.module('FactoryExample',[]);var factoryController = app.controller('FactoryController', FactoryController);var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);
//first implementation where it returns a functionfunction NameOfTheFactoryOne(){var factory = function(){return new SomeService();}return factory;}
//second implementation where an object literal would be returnedfunction NameOfTheFactoryTwo(){var factory = {getSomeService : function(){return new SomeService();}};return factory;}

现在在控制器中使用上述两个:

 var factoryOne = NameOfTheFactoryOne() //since it returns a functionfactoryOne.someMethod();
var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the objectfactoryTwo.someMethod();

工厂特点:

  1. 遵循工厂设计模式。工厂是生产新对象或新功能的中心场所。
  2. 不仅产生单例,而且产生可定制的服务。
  3. .service()方法是一个工厂方法,它总是生成相同类型的服务,这是一个单例,并且没有任何简单的方法来配置它的行为。那个.service()方法通常用作不需要任何配置的东西的快捷方式。

供应商

让我们先看一下语法:

angular.module('ProviderModule', []).controller('ProviderModuleController', ProviderModuleController).provider('ServiceProvider', ServiceProvider).config(Config); //optional
Config.$inject = ['ServiceProvider'];function Config(ServiceProvider) {ServiceProvider.defaults.maxItems = 10; //some default value}

ProviderModuleController.$inject = ['ServiceProvider'];function ProviderModuleController(ServiceProvider) {//some methods}
function ServiceProvider() {var provider = this;
provider.defaults = {maxItems: 10};
provider.$get = function () {var someList = new someListService(provider.defaults.maxItems);
return someList;};}
}

供应商的特点:

  1. Provider是在Angular中创建服务的最灵活方法。
  2. 我们不仅可以创建一个可动态配置的工厂,而且在使用工厂时,使用提供者方法,我们可以在整个应用程序的无融资创业中自定义配置工厂一次。
  3. 然后可以通过自定义设置在整个应用程序中使用工厂。换句话说,我们可以在应用程序启动之前配置此工厂。事实上,在角留档中提到,当我们使用.service.factory方法配置我们的服务时,提供者方法实际上是在幕后执行的。
  4. $get是一个直接附加到提供者实例的函数。该函数是工厂函数。换句话说,它就像我们用于提供.factory方法的那个。在该函数中,我们创建了自己的服务。这个#0属性,这是一个函数,是使提供者成为提供者的原因AngularJS希望提供者有一个$get属性,其值是Angular将其视为工厂函数的函数。但是,整个提供者设置非常特别的是,我们可以在服务提供者内部提供一些config对象,并且通常带有默认值,我们可以稍后在步骤中覆盖这些默认值,我们可以在其中配置整个应用程序。

本质上,Provider、Factory和Service都是服务。工厂是服务的特例,当你只需要一个$get()函数时,允许你用更少的代码编写它。

服务、工厂和提供商之间的主要区别在于它们的复杂性。服务是最简单的形式,工厂更健壮,提供商在运行时是可配置的。

以下是何时使用每个的摘要:

工厂:您提供的价值需要根据其他数据计算。

服务:您正在返回一个带有方法的对象。

提供商:您希望能够在配置阶段配置将在创建之前创建的对象。在应用程序完全初始化之前,主要在应用程序配置中使用提供程序。

在阅读了所有这些帖子之后,它给我带来了更多的困惑…但仍然都是有价值的信息…最后我找到了下表,它将提供简单比较的信息

  • 注入器使用配方创建两种类型的对象:服务和特殊用途对象
  • 有五种配方类型定义了如何创建对象:值,工厂,服务,供应商和常量。
  • 工厂和服务是最常用的配方。它们之间的唯一区别是服务配方更适合自定义类型的对象,而工厂可以生成JavaScript原语和函数。
  • 提供者配方是核心配方类型,所有其他的只是语法糖。
  • Provider是最复杂的配方类型。除非您正在构建需要全局配置的可重用代码段,否则您不需要它。
  • 除控制器之外的所有特殊用途对象都通过工厂配方定义。

在此处输入图片描述

对于初学者了解:-这可能不正确的用例,但在高层次上,这是这三个的用例。

  1. 如果要在角度模块中使用配置函数应创建为提供商

angular.module('myApp').config(function($testProvider){$testProvider.someFunction();})

  1. Ajax调用或第三方集成需要服务
  2. 对于数据操作,将其创建为工厂

对于基本场景,工厂和服务的行为相同。

所有的好答案都已经有了。我想在服务工厂上再补充几点。除了服务/工厂之间的区别。还有一个问题,比如:

  1. 我应该使用服务还是工厂?有什么区别?
  2. 他们是做同样的事还是有同样的行为?

让我们从服务和工厂之间的区别开始:

  1. 都是Singleton:每当Angular第一次发现这些作为依赖项时,它都会创建一个服务/工厂实例。一旦创建了实例,就永远使用同一个实例。

  2. 可用于对具有行为的对象建模:它们都可以有方法、内部状态变量等。尽管你编写代码的方式会有所不同。

服务:

服务是一个构造函数,Angular将通过调用newyourServiceName()来实例化它。这意味着几件事。

  1. 函数和实例变量将是this的属性。
  2. 你不需要返回一个值。当Angular调用new yourServiceName()时,它会收到this对象以及你放在它上面的所有属性。

示例:

angular.service('MyService', function() {this.aServiceVariable = "Ved Prakash"this.aServiceMethod = function() {return //code};});

当Angular将这个MyService服务注入到一个控制器中时取决于它,该控制器将获得它可以调用的MyService函数,例如MyService. aServiceWay()。

小心点#0

由于构造的服务是一个对象,它里面的方法在被调用时可以引用:

angular.service('ScoreKeeper', function($http) {this.score = 0;
this.getScore = function() {return this.score;};
this.setScore = function(newScore) {this.score = newScore;};
this.addOne = function() {this.score++;};});

你可能会想在Promise链中调用ScoreKeeper.setScore,例如,如果你通过从服务器抓取它来初始化分数:$http.get('/score').then(ScoreKeeper.setScore).这样做的问题是ScoreKeeper.setScore会被调用,this绑定到null,你会得到错误。更好的方法是$http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))。无论您是否选择在服务方法中使用它,请注意如何调用它们。

从#0返回一个值

由于JavaScript构造函数的工作方式,如果您从constructor函数返回复杂值(i.e., an Object),调用者将获得该Object而不是this实例。

这意味着你基本上可以从下面复制粘贴工厂示例,将factory替换为service,它就可以工作了:

angular.service('MyService', function($http) {var api = {};
api.aServiceMethod= function() {return $http.get('/users');};return api;});

因此,当Angular使用new MyService()构建您的服务时,它将获得该api对象而不是MyService实例。

这是任何复杂值(对象、函数)的行为,但不适用于原始类型。

工厂:

工厂是一个返回值的普通旧函数。返回值是被注入到依赖于工厂的东西中的内容。Angular中典型的工厂模式是返回一个以函数为属性的对象,如下所示:

angular.factory('MyFactory', function($http) {var api = {};
api.aFactoryMethod= function() {return $http.get('/users');};
return api;});

工厂依赖项的注入值是工厂的返回值值,它不一定是对象。它可以是一个函数

以上1、2个问题解答:

在大多数情况下,只需坚持使用工厂即可。他们的行为更容易理解,我们别无选择关于是否返回一个值,此外,没有错误如果你做了错误的事情。

当我谈论注射时,我仍然将它们称为“服务”#36825;的依赖关系

Service/Factory的行为非常相似,有人会说任何一个都可以。这有点真实,但我发现更容易遵循John Papa的风格指南的建议,坚持下去工厂。**