在一个分层良好的 Angular 应用中,Controller 这一层应该很薄。也就是说,应用里大部分的业务逻辑和持久化数据都应该放在 Service 里。

为此,理解 AngularJS 中的几个 Provider 之间的区别很有必要。

Provider 创建的新服务都可以用来注入。包括:

  • provider
  • factory
  • service
  • constant
  • value

另外,内建的服务 $controller 和 $filter 也可以被注入,同时也可以使用这些服务来获得新的过滤器和控制器。

下面介绍一下各自的用法和 provider、factory、value 三者之间的区别。

provider

用于产生一个可配置的 Service,由两部分组成。第一部分的变量和函数是可以在 app.config 函数中访问的,可以在它们被其他地方访问到之前来修改它们。定义方式如下:

1
2
3
4
app.provider('myProvider', function(){
var a = '';
var func = function(){};
})

在 app.config 函数对 a 进行修改:

1
2
3
app.config(function(myProviderProvider){
myProvider.a = 'hello world';
})

这也是在有如此简单的 factory 的情况下还使用 provider 的原因。

第二部分的变量和函数是通过 $get() 函数返回的,可以在任何传入了该 provider 的控制器中进行访问的。

1
2
3
4
5
6
7
8
app.provider('myProvider', function(){
this.$get = function(){
return {
foo: function(){},
a: a
}
}
})

factory

factory 返回一个对象。只需要创建一个对象,为它添加属性,然后返回这个对象。在控制器中注入该 factory,即可使用它的所有属性。

1
2
3
4
5
6
app.factory('myFactory', function(){
var fac = {};
fac.a = 'hello world';
fac.foo = function(){};
return fac;
})

看得出来,factory 的第二个参数就是 provider 中 $get 要对应的函数实现。

service

service 类似于一个构造器, 通过 new 关键字实例化对象,将一些属性和方法直接添加到 this上,在创建 service 对象时,this 会被作为返回值返回。

1
2
3
4
5
6
app.service('myService', function(){
var a = '';
this.setA = function(){};
this.getA = function(){};
this.foo = function(){};
})

注入 myService 的控制器可以访问到绑定在 myService 中 this 上的 setA() , getA() 和foo() 三个方法。

constant

constant 用于定义常量,一旦定义就不能被改变。可以被注入到任何地方,但是不能被装饰器(decorator)装饰。

1
app.constant('APP_KEY', 'a1s2d3f4')

value

与 constant 一样,可以用来定义值。但与 constant 的区别是:可以被修改,可以被 decorator 装饰,不能被注入到 config 中。

1
app.value('version', '1.0')

value 通常用来为应用设置初始值。

decorator

比较特殊,它不是 provider 。它是用来装饰其他 provider 的,不过 constant 除外,因为从源码可以看出,constant 不是通过 provider() 方法创建的。

下面是一个用 decorator 装饰 value 的栗子。

1
2
3
4
app.value('version', '1.0');
app.decorator('version', function ($delegate) {
return $delegate + '.1';
})

那如果要使用前面的 myService service,但是其中缺少一个你想要的 greet 函数。可以修改 service 吗?答案是不行!但是可以装饰它:

1
2
3
4
5
app.decorator('myService', function($delegate){
$delegate.greet = function(){
return "Hello, I am a new function of 'myService'";
}
})

$delegate 代表实际上的 service 实例。

装饰一个 service 的能力是非常实用的,尤其是当我们想要使用第三方的 service 时,此时不需要将代码复制到我们的项目中,而只需要进行一些修改即可。

源码

下面是 provider、factory、service、value、constant 和 decorator 的底层实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
provider_ = providerInjector.instantiate(provider_);
}
if (!provider_.$get) {
throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
}
return providerCache[name + providerSuffix] = provider_;
} function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
} function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
} function value(name, val) { return factory(name, valueFn(val), false); } function constant(name, value) {
assertNotHasOwnProperty(name, 'constant');
providerCache[name] = value;
instanceCache[name] = value;
} function decorator(serviceName, decorFn) {
var origProvider = providerInjector.get(serviceName + providerSuffix),
orig$get = origProvider.$get; origProvider.$get = function() {
var origInstance = instanceInjector.invoke(orig$get, origProvider);
return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
};
}

可以看出,除了 constant,另外几个最终调用的都是 provider(decorator比较特殊,不算)。

总结

什么时候使用 provider 而不用 factory ?

provider 是 factory 的加强版。当需要一个可配置的 factory 的时候,使用 provider。

简单介绍一下 AngularJS 运行应用的过程,分两个阶段,config 阶段和 run 阶段。config 阶段是设置任何的 provider 的阶段。也是设置任何的指令,控制器,过滤器以及其它东西的阶段。在 run 阶段,AngularJS 会编译你的 DOM 并启动应用。

factory 和 service 的区别是什么?

factory 是普通 function,而 service 是一个构造器(constructor),这样 Angular 在调用 service 时会用 new 关键字,而调用 factory 时只是调用普通的 function,所以 factory 可以返回任何东西,而 service 可以不返回。

参考

  1. AngularJS 之 Factory vs Service vs Provider
  2. [AngularJS系列(4)] 那伤不起的provider们啊~ (Provider, Value, Constant, Service, Factory, Decorator)
  3. 理解AngularJS中的Service类型
  4. AngularJS中的Provider们:Service和Factory等的区别

AngularJS 中 Provider 的用法及区别的更多相关文章

  1. angularjs中provider,factory,service的区别和用法

    angularjs中provider,factory,service的区别和用法 都能提供service,但是又有差别 service 第一次被注入时实例化,只实例化一次,整个应用的生命周期中是个单例 ...

  2. AngularJS中forEach的用法

    AngularJS中当我们需要遍历某个数组的时候,我们会用到forEach语法.AngularJS中forEach的用法如下: angular.forEach(array,function(obj,i ...

  3. AngularJS中$interval的用法

    在AngularJS中$interval用来处理间歇性处理一些事情. 最常用的是: var app = angular.module("app",[]); app.controll ...

  4. AngularJS 服务 provider factory service及区别

    一.概念说明 1.服务是对公共代码的抽象,如多个控制器都出现了相似代码,把他们抽取出来,封装成一个服务,遵循DRY原则,增强可维护性,剥离了和具体表现相关的部分,聚焦于业务逻辑或交互逻辑,更加容易被测 ...

  5. angularjs中ng-switch的用法

    <!DOCTYPE html> <html lang="zh-CN" ng-app="app" ng-controller="ctr ...

  6. angularjs中$parse的用法

    转载自:https://umur.blog/2014/02/25/advanced-angular-parse/ 高级Angular:$ parse 如果你想加强你的AngularJS知识,$ par ...

  7. AngularJS中ng-options简单用法及预选项失败的原因

    刚刚接触AngularJs,记录一下ng-options的使用. 1.构造key-value数据 $scope.types = [ {id:"1",type:"AA&qu ...

  8. angularjs 中的$digest和$apply区别

    $digest和$apply 在Angular中,有$apply和$digest两个函数,我们刚才是通过$digest来让这个数据应用到界面上.但这个时候,也可以不用$digest,而是使用$appl ...

  9. Mybatis的mapper文件中$和#的用法及区别详解

    https://www.2cto.com/database/201806/752139.html用了一段时间的Mybatis了,对于$和#的用法老是很迷糊,特此记下加深记忆. 简单来说 #{} 会在将 ...

随机推荐

  1. Qt Creator的下载、安装及试用

    1.试用环境及版本介绍:本文介绍的是windows桌面平台下使用Qt4.7.2和Qt Creator2.1.0,其他操作系统和版本在阅读时请留意. 2.下载: 从http://get.qt.nokia ...

  2. vagrant多节点配置

    1.vagrantfile的配置 Vagrant.configure("2") do |config| config.vm.box = "xinjieLinux" ...

  3. HDU 3436 Queue-jumpers

    题意: n个人站成一排  一開始是从1到n有序的  如今有三个操作  Top操作是将一个人排到队首  Query操作是询问某个人如今排第几  Rank操作是询问排某个位置的人是谁 思路: 将队伍扭来扭 ...

  4. Zookeeper常用命令 (转)

    原文链接:ZooKeeper系列之二:Zookeeper常用命令 ZooKeeper服务命令: 在准备好相应的配置之后,可以直接通过zkServer.sh 这个脚本进行服务的相关操作 1. 启动ZK服 ...

  5. (转)[ActionScript 3] Google-ProtoBuf for AS

    最近由于项目的需要,研究了一下protobuf.在这里分享一下经验,具体介绍网上也有不少,可以百度先了解一下. ProtoBuf在as中主要就是序列反序列化的作用,我们主要用它来代替amf,因为像c+ ...

  6. XPath查找节点值示例

    下面一个XML文档,需要找到粗体部分文字: <?xml version='1.0' encoding='utf-8'?> <rep sts="OK" a=&quo ...

  7. java梳理-一个汉字占多大空间

    面试题:一个汉字占多大空间. 事实上这个问题我了解不深的,知道结论不知道为什么.借此梳理下认识. 先回想下java基本类型 一基本类型 :简称四类八种,声明变量的同一时候分配了空间.举比例如以下:   ...

  8. SQLServer 之 聚合函数

    一.聚合函数介绍 1.聚合函数最常用的: (1) COUNT:求个数 count函数用于计算满足条件的数据项数,返回int数据类型的值. [1] 语法结构:COUNT( {[[ all | disti ...

  9. 创建sdcard.img时,提示permission dennid

    解决方法: mksdcard -l sdcard 100M E:\sdcard\sdcard.img 换一个盘试试,比如:mksdcard -l sdcard 100M F:\sdcard\sdcar ...

  10. ASP.NET Core Kestrel 随机404错误

    一.Bug 出现 最近遇到一个很诡异的bug,Visual Studio 2017调试ASP.NET Core 2.2 Web程序的时候,随机性的出现404错误.如下图 事实上这个css文件是存在的, ...