AngularJS中的服务、提供商和工厂之间有什么区别?
当前回答
对我来说,当我意识到它们都以相同的方式工作时,我就发现了这一点:通过运行一次某个东西,存储它们获得的值,然后在通过依赖注入引用时提取相同的存储值。
假设我们有:
app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);
三者之间的区别在于:
a的存储值来自运行fn。b的存储值来自newing fn。c的存储值来自首先通过newing fn获取一个实例,然后运行该实例的$get方法。
这意味着在AngularJS中有一个类似于缓存对象的东西,每次注入的值仅在第一次注入时分配一次,其中:
cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()
这就是为什么我们在服务中使用这个,并定义一个This$获取提供者。
其他回答
使用此页面和文档作为参考(自上次查看以来似乎有了很大的改进),我整理了以下真实世界演示,其中使用了提供者的5种风格中的4种;价值、常量、工厂和全面供应商。
HTML格式:
<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>
app
var app = angular.module('angularProviders', []);
// A CONSTANT is not going to change
app.constant('range', 100);
// A VALUE could change, but probably / typically doesn't
app.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 CONSTANT
return 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 currency
this.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 value
Money.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 provider
this.setLocale = function(value) {
locale = value;
};
// All providers need to implement a $get method which returns
// an instance of the custom class which constitutes the service
this.$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 controller
app.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 provider
this.earn = money.convertValue(random); // random is computed @ runtime
this.earned = money.convertValue(0);
this.handleClick = function() {
this.count ++;
this.earned = money.convertValue(random * this.count);
};
});
工作演示。
本质上,供应商、工厂和服务都是服务。工厂是服务的一种特殊情况,您只需要一个$get()函数,这样您就可以用更少的代码编写它。
服务、工厂和供应商之间的主要区别在于其复杂性。服务是最简单的形式,工厂更健壮,提供者在运行时可配置。
以下是何时使用每一项的摘要:
工厂:需要根据其他数据计算您提供的值。
服务:您正在返回带有方法的对象。
提供者:您希望能够在配置阶段配置将在创建之前创建的对象。在应用程序完全初始化之前,主要在应用程序配置中使用Provider。
Angular文档摘要:
有五种配方类型定义了如何创建对象:Value,工厂、服务、供应商和常量。工厂和服务是最常用的配方。它们之间的唯一区别是,Service配方对自定义类型的对象更有效,而Factory可以生成JavaScript原语和函数。提供者配方是核心配方类型,所有其他配方都只是其语法上的糖。提供程序是最复杂的配方类型。除非您正在构建一段需要全局配置的可重用代码,否则您不需要它。
SO的最佳答案:
https://stackoverflow.com/a/26924234/165673(<--良好)https://stackoverflow.com/a/27263882/165673https://stackoverflow.com/a/16566144/165673
我知道很多很好的答案,但我必须分享我的使用经验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;
...
派对有点晚了。但我认为这对那些想学习(或清楚)如何使用工厂、服务和提供者方法开发Angular JS自定义服务的人更有用。
我看到了这段视频,它清楚地解释了开发AngularJS定制服务的工厂、服务和供应商方法:
https://www.youtube.com/watch?v=oUXku28ex-米
源代码:http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service
此处发布的代码直接从上述来源复制,以使读者受益。
基于“工厂”的定制服务的代码如下(它与同步和异步版本一起调用http服务):
var app=角度模块(“app”,[]);app.controller('imp',['$scope','calcFactory',函数($scope,calcFactory){$scope.a=10;$scope.b=20;$scope.doSum=函数(){//$scope.sum=calcFactory.getSum($scope.a,$scope.b)//同步的calcFactory.getSum($scope.a,$scope.b,函数(r){//aynchronous$scope.sum=r;});};}]);app.factory('calFactory',['$http','$log',函数($http,$log){$log.log(“实例化calcFactory.”);var oCalcService={};//oCalcService.getSum=函数(a,b){//返回parseInt(a)+parseInt(b);//};//oCalcService.getSum=函数(a,b,cb){//var s=parseInt(a)+parseInt(b);//cb(s);//};oCalcService.getSum=函数(a,b,cb){//使用http服务$http({url:'http://localhost:4467/Sum?a='+a+'和b='+b,方法:'GET'}).然后(函数(resp){$log.log(对应数据);cb(相应数据);},函数(resp){$log.error(“出现错误”);});};return oCalcService;}]);
自定义服务的“服务”方法的代码(这与“工厂”非常相似,但从语法角度来看不同):
var app=角度模块(“app”,[]);app.controller('imp',['$scope','calcService',函数($scope,calcService){$scope.a=10;$scope.b=20;$scope.doSum=函数(){//$scope.sum=calcService.getSum($scope.a,$scope.b);calcService.getSum($scope.a,$scope.b,函数(r){$scope.sum=r;}); };}]);app.service('calService',['$http','$log',函数($http,$log){$log.log(“实例化calcService..”);//this.getSum=函数(a,b){//返回parseInt(a)+parseInt(b);//};//this.getSum=函数(a,b,cb){//var s=parseInt(a)+parseInt(b);//cb(s);//};this.getSum=函数(a,b,cb){$http({url:'http://localhost:4467/Sum?a='+a+'和b='+b,方法:'GET'}).然后(函数(resp){$log.log(对应数据);cb(相应数据);},函数(resp){$log.error(“出现错误”);});};}]);
自定义服务的“提供者”方法的代码(如果您想开发可配置的服务,这是必要的):
var app=角度模块(“app”,[]);app.controller('imp',['$scope','calcService',函数($scope,calcService){$scope.a=10;$scope.b=20;$scope.doSum=函数(){//$scope.sum=calcService.getSum($scope.a,$scope.b);calcService.getSum($scope.a,$scope.b,函数(r){$scope.sum=r;}); };}]);app.provider('calService',函数(){var baseUrl=“”;this.config=函数(url){baseUrl=url;};这一点$get=['$log','$http',函数($log,$http){$log.log(“正在实例化calcService…”)var oCalcService={};//oCalcService.getSum=函数(a,b){//返回parseInt(a)+parseInt(b);//};//oCalcService.getSum=函数(a,b,cb){//var s=parseInt(a)+parseInt(b);//cb(s); //};oCalcService.getSum=函数(a,b,cb){$http({url:baseUrl+'/Sum?a=‘+a+’&b=‘+b,方法:'GET'}).然后(函数(resp){$log.log(对应数据);cb(相应数据);},函数(resp){$log.error(“出现错误”);});}; return oCalcService;}];});app.config(['calServiceProvider',函数(calServiceProvider){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>a的值为{{a}},但你可以改变<input-type=text-ng-model=“a”/><br>b的值是{{b}},但你可以改变<input-type=text-ng-model=“b”/><br></div>总和={{Sum}}<br><button ng click=“doSum()”>计算</button></div></body></html>
推荐文章
- angularjs中的compile函数和link函数有什么区别
- 如何向一个5岁的孩子解释依赖注入?
- Ng-repeat结束事件
- 缓存一个HTTP 'Get'服务响应在AngularJS?
- 从ng-click获取原始元素
- Angular JS:当我们已经有了具有作用域的指令控制器时,指令的link函数还需要什么?
- Angularjs的ng-model不能在ng-if中工作
- AngularJS禁用了开发机器上的部分缓存
- 如何在AngularJS中动态添加指令?
- 如何在AngularJS中观察路由变化?
- 实例化模块失败[$injector:unpr]未知提供者:$routeProvider
- 在AngularJS中集成jQuery插件的正确方法
- 如何设置一个iframe src属性从一个变量在AngularJS
- 如何在Angular中使用$rootScope来存储变量?
- AngularJS:工厂和服务?