AngularJS中的服务、提供商和工厂之间有什么区别?
当前回答
让我们以简单的方式讨论AngularJS中处理业务逻辑的三种方法:(灵感来自Yaakov的Coursera AngularJS课程)
服务:
语法:
应用程序.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;
}
}
索引html
<div ng-controller = "ServiceExampleController as serviceExample">
{{serviceExample.data}}
</div>
服务特点:
懒惰实例化:如果它没有被注入,就永远不会被实例化。因此,要使用它,必须将其注入到模块中。Singleton:如果注入到多个模块,所有模块都只能访问一个特定的实例。这就是为什么在不同控制器之间共享数据非常方便的原因。
工厂
首先让我们看看语法:
应用.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 function
function NameOfTheFactoryOne(){
var factory = function(){
return new SomeService();
}
return factory;
}
//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
var factory = {
getSomeService : function(){
return new SomeService();
}
};
return factory;
}
现在在控制器中使用以上两个:
var factoryOne = NameOfTheFactoryOne() //since it returns a function
factoryOne.someMethod();
var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
factoryTwo.someMethod();
工厂特点:
遵循工厂设计模式。工厂是生产新对象或功能的中心场所。不仅生成单例,还生成可定制的服务。.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;
};
}
}
提供商的特点:
Provider是在Angular中创建服务的最灵活的方法。我们不仅可以创建一个可动态配置的工厂,而且在使用工厂时,通过提供程序方法,我们可以在整个应用程序启动时自定义配置工厂一次。然后,工厂可以在整个应用程序中使用自定义设置。换句话说,我们可以在应用程序启动之前配置此工厂。事实上,在angular文档中提到,当我们使用.service或.factory方法配置服务时,提供者方法实际上是在幕后执行的。$get是一个直接附加到提供程序实例的函数。该函数是工厂函数。换句话说,它就像我们用来提供给.factory方法的一样。在该函数中,我们创建自己的服务。这个$get属性是一个函数,它使提供者成为提供者。AngularJS希望提供程序具有$get属性,该属性的值是Angular将作为工厂函数处理的函数。但使整个提供程序设置非常特殊的是,我们可以在服务提供程序内部提供一些配置对象,这通常带有默认值,我们可以稍后在步骤中覆盖这些默认值,在该步骤中我们可以配置整个应用程序。
其他回答
已经有好的答案了,但我只想分享这个答案。
首先:Provider是创建服务(单例对象)的方法/方法,该服务假设由$injector注入(AngulaJS如何处理IoC模式)。
以及价值、工厂、服务和常量(4种方式)——相对于提供者方式/接收器的语法糖。
服务与工厂部分已涵盖:https://www.youtube.com/watch?v=BLzNCkPn3ao
服务都是关于新关键字的,实际上我们知道它有四个方面:
创建全新对象将其链接到其原型对象将上下文连接到此并返回此
工厂就是工厂模式的全部内容——包含返回类似服务的对象的函数。
使用其他服务的能力(具有依赖关系)服务初始化延迟/延迟初始化
这个简单/简短的视频:还包括提供商:https://www.youtube.com/watch?v=HvTZbQ_hUZY(在那里你可以看到他们是如何从工厂走向供应商的)
在应用程序完全启动/初始化之前,主要在应用程序配置中使用提供程序配方。
所有的好答案都已经有了。我想在服务和工厂方面再补充几点。以及服务/工厂之间的差异。你也可以有这样的问题:
我应该使用服务还是工厂?有什么不同?他们的行为是否相同?
让我们从服务和工厂之间的区别开始:
两者都是Singleton:每当Angular第一次发现它们作为依赖项时,它都会创建服务/工厂的单个实例。创建实例后,将永远使用同一实例。可用于对具有行为的对象进行建模:它们都可以有方法、内部状态变量等。尽管编写代码的方式会有所不同。
服务:
服务是一个构造函数,Angular将通过调用newyourServiceName()来实例化它。这意味着一些事情。
函数和实例变量将是它的财产。您不需要返回值。当Angular调用new yourServiceName()时,它将接收此对象以及您在其上放置的所有财产。
示例:
angular.service('MyService', function() {
this.aServiceVariable = "Ved Prakash"
this.aServiceMethod = function() {
return //code
};
});
当Angular将此MyService服务注入控制器时取决于它,该控制器将获得它可以调用的MyService上的函数,例如MyService.aServiceMethod()。
注意:
由于构造的服务是一个对象,因此当调用它们时,它内部的方法可以引用它:
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++;
};
});
例如,如果您通过从服务器$http.get('/score').then(ScoreKeeper.setScore)获取分数来初始化分数,那么您可能会尝试在承诺链中调用ScoreKeeper。这样做的问题是,ScoreKeeer.setScore将在该绑定为空的情况下被调用,并且您会收到错误。更好的方法是$http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))。无论您是否选择在服务方法中使用它,请注意如何调用它们。
从服务返回值:
由于JavaScript构造函数的工作方式,若从构造函数函数返回一个复杂值(即Object),调用者将获得该Object而不是该实例。
这意味着你基本上可以从下面复制粘贴工厂示例,用服务替换工厂,它会起作用:
angular.service('MyService', function($http) {
var api = {};
api.aServiceMethod= function() {
return $http.get('/users');
};
return api;
});
因此,当Angular使用新的MyService()构造服务时,它将获得该api对象而不是MyService实例。
这是任何复杂值(对象、函数)的行为,但不是基本类型的行为。
工厂:
工厂是一个返回值的普通旧函数。返回值是注入到依赖于工厂的事物中的值。Angular中的一个典型工厂模式是返回一个具有函数作为财产的对象,如下所示:
angular.factory('MyFactory', function($http) {
var api = {};
api.aFactoryMethod= function() {
return $http.get('/users');
};
return api;
});
工厂依赖项的注入值是工厂的返回值值,并且它不必是对象。这可能是一种功能
以上1和2个问题的答案:
大多数情况下,只要坚持使用工厂就可以了。他们的行为更容易理解。别无选择关于是否返回一个值,此外,没有错误如果你做错事,就会被介绍。当我谈论注射时,我仍然将其称为“服务”但它们是依赖关系。服务/工厂行为非常相似,有些人会说任何一个都很好。这有点正确,但我觉得遵循约翰·帕帕风格指南的建议,坚持工厂**
我注意到了一些有趣的事情,当我和提供者一起玩的时候。
与服务和工厂相比,供应商对注射剂的可见性有所不同。如果您声明AngularJS“常量”(例如,myApp.constant('a','Robert');),您可以将其注入服务、工厂和提供商。
但是如果您声明一个AngularJS“value”(例如,myApp.value('b',{name:'Jones‘});),您可以将其注入服务和工厂,但不能注入提供程序创建函数。但是,您可以将其注入为提供者定义的$get函数中。AngularJS文档中提到了这一点,但很容易错过。您可以在%provide页面的value和constant方法部分找到它。
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>
为了澄清这一点,从AngularJS源代码中,您可以看到一个服务只是调用工厂函数,而工厂函数反过来调用提供程序函数:
function factory(name, factoryFn) {
return provider(name, { $get: factoryFn });
}
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
此答案针对主题/问题
Factory、Service和Constant是如何在提供者配方之上添加语法糖的?
OR
工厂、服务和供应商在内部是怎样的
基本上发生的是
当您创建factory()时,它会将第二个参数中提供的函数设置为provider的$get并返回它(provider(name,{$get:factoryFn})),您所得到的只是provider,但除了$get之外没有其他属性/方法(这意味着您无法配置)
工厂源代码
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
};
当生成服务()时,它返回您提供factory()的函数,该函数注入构造函数(返回您在服务中提供的构造函数的实例)并返回它
服务源代码
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
};
因此,基本上在这两种情况下,您最终都会将providers$get设置为您提供的函数,但您可以提供$get以外的任何内容,因为您最初可以在provider()中为config块提供
推荐文章
- AngularJS控制器的生命周期是什么?
- $destroy是否删除事件监听器?
- 用布尔值将单选按钮绑定到模型
- AngularJS只适用于单页应用程序吗?
- angular.js中的内联条件
- 如何突出显示当前菜单项?
- 如何使用AngularJS获取url参数
- angularjs中的compile函数和link函数有什么区别
- 如何向一个5岁的孩子解释依赖注入?
- Ng-repeat结束事件
- 缓存一个HTTP 'Get'服务响应在AngularJS?
- 从ng-click获取原始元素
- Angular JS:当我们已经有了具有作用域的指令控制器时,指令的link函数还需要什么?
- Angularjs的ng-model不能在ng-if中工作
- AngularJS禁用了开发机器上的部分缓存