文章目录
  1. 1. 关于服务
  2. 2. 创建服务
    1. 2.1. factory()
    2. 2.2. service()
    3. 2.3. provider()
    4. 2.4. constant()与value()
    5. 2.5. decorator()
  3. 3. 使用服务
  4. 4. 服务源码实现
  5. 5. 引用文章

服务是一个单例对象,在每个应用中只会被实例化一次,并且是延迟加载的(在需要时才会被创建)。 优点:

  1. 为应用提供通用的服务,形式可以是常量或对象
  2. 便于模块化
  3. 便于单元测试

关于服务

出于内存占用和性能的考虑,控制器只会在需要时被实例化,并且不再需要就会被销毁,这意味着每次切换路由或重新加载视图时,当前的控制器会被AngularJs 清除掉。
服务提供了一种能在应用的整个生命周期内保持数据的方法,它能够在控制器之间进行通信,并且能保证数据的一致性。服务也是在控制器之间共享数据的典型方法。
AngularJs 提供了一些内置服务,如$http,任何地方使用这些内置服务都是统一的,并且根据我们自己的应用需要我们也可以创建自己的服务。

创建服务

自己创建服务也是很容易的:只需要注册这个服务即可。服务被注册后,AngularJS 编译器就可以引用它,并且在运行时把它当做依赖加载进来。
在AngularJS中 ,有五种方法可以用来注册服务:

factory()
service()
constant()
value()
provider()

factory()

factory() 方法是用来注册服务的最常规的方式。
factoty() 接收两个参数:name (字符串) 和 getFn(函数)。形式如下:

1
2
3
4
5
6
angular.module('myApp')
.factoty('myService'function(){
return {
}
})

因为服务是单例对象,getFn在应用的声明周期只会被调用一次。同其他的AngularJS的服务一样,在定义服务时,getFn可以接受一个包含可被注入对象的数组或函数。

service()

service() 可以注册一个支持构造函数的服务,它允许我们为服务对象注册一个构造函数。
service() 接受两个参数: name(字符串)和 constructor(函数)。constructor 是构造函数,用来调用它实例化服务的对象。service()函数会在创建实例时通过new关键字来实例化服务对象。 形式如下:

1
2
3
4
5
6
7
var Person = function(){
this.getName = function(){
}
}
angular.module('myApp')
.service('myService',Person);

provider()

所有服务都是由$provide服务创建的,$provide 服务负责在运行时初始化这些提供者。 提供者是一个具有$get()方法的对象,$injector通过调用$get方法创建服务实例。
所有创建服务的方法都构建在provider方法之上。provider()方法负责在$providerCache中注册服务。
provider() 方法可以接受两个参数:name(字符串)和 aProvider(对象/函数/数组)。

name : name参数在providerCache中是注册的名字。name+Provider 会成为服务的提供者。name也是服务实例的名字。
aProvider 可以是多种形式。

1. aProvider是个函数,那么它会通过依赖注入被调用,并且负责通过$get方法返回一个对象。
2. aProvider是个数组,会被当成一个带有行内依赖注入声明的函数来处理。数组的最后一个元素应该是函数,可以返回一个带有$get方法的对象。
3. aProvider 是个对象,则应该带有$

provider()函数会返回一个已经注册的提供者实例。直接使用provider()是最原始的创建服务的方法。

1
2
3
4
5
6
7
8
9
10
11
angular.module('myApp',[])
.provider('myService',{
a:"ss",
$get:function(){
return{
geta:function(){
return this.a;
}
}
}
})

当我们给provider()函数传入的就是$get()方法时,factory()函数就是用provider()方法注册服务的简化形式.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 下面这两种方法作用相同
angular.module('myApp')
.factory('myService',function(){
return{
username:"ss"
}
})
.provider('myService',{
$get:function(){
return {
username:'ss'
}
}
})

是否可以一直使用.factoty()方法代替.provider()呢? 答案在于 是否需要用AngularJS的.config() 函数来对.provider()方法返回的服务进行额外的配置。
先注册一个服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 下面这两种方法作用相同
angular.module('myApp')
.provider('myService',function(){
var myUrl = "ss";
function setUrl (url){
if(url){
myUrl =url;
}
}
$get:function(){
return {
}
}
})

若是想在应用启动前配置 myService 的URL ,则:

1
2
3
4
angular.module('myApp',[])
.config(function(myServiceProdiver){
myServiceProdiver.setUrl("xx.com");
})

在上面的栗子中,provider() 在myService 后面添加Provider生成一个新的提供者,myServiceProdiver可以被注入到config()
如果希望在config中可以对服务进行配置,必须使用provider()来定义服务。

constant()与value()

constant()可以将一个已经存在的常量注册为服务,并可以注入到其他的任何地方。
constant() 接收两个参数name 和 value.
constant() 注册的常量服务,不能被装饰器拦截。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var app = angular.module('app', []);
app.constant('PI', 3.14159265359);
app.config(function(PI){
var radius = 4;
//PI can be injected here in the config block
var perimeter = 2 * PI * radius;
});
app.controller('appCtrl', function(PI) {
var radius = 4;
// calculate area of the circle
var area = PI * radius * radius;
});

value()可以将一个已经存在的变量注册为服务,不能注入在 config 的方法中。
value() 接收两个参数name 和 value.

1
2
3
4
5
6
7
8
9
var app = angular.module('app', []);
app.value('greeting', 'Hello');
app.config(function ($provide) {
$provide.decorator('greeting', function ($delegate) {
return $delegate + ' World!';
});
});

decorator()

$provide 服务提供了在服务实例创建时对其进行拦截的功能,并可以对服务进行扩展,或者用另外的内容替换它。
对服务进行装饰的场景有很多,比如对服务进行扩展,将外部数据缓存进localStorage的功能,或者对服务进行封装以便在开发中进行调试和跟踪。
对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
var upstream = angular.module('thirdParty', []);
upstream.service('emailService', function() {
this.email = "";
this.setContent = function(content) {
this.email = content;
};
this.send = function(recipient) {
return 'sending "' + this.email + '" to ' + recipient;
};
});
var app = angular.module('myApp', ['thirdParty']);
app.config(function($provide) {
$provide.decorator('emailService', function($delegate) {
// myApp depends on the emailService from a third-party module, but the service is lacking a way to send email with signature.
// To avoid reinventing the wheel and, as well as, maintaining a good habit of leaving third-party module intact,
// I use $provide.decorator here to enhance emailService.
$delegate.sendWithSignature = function(recipient, signature) {
return 'sending "' + this.email + '" to ' + recipient + " by " + signature;
};
return $delegate;
});
});
app.controller('MainCtrl', function($scope, emailService) {
emailService.setContent("Greeting!!");
$scope.emailComplete = emailService.sendWithSignature('a@a.com', 'tamakisquare');
});

使用服务

可以在控制器、指令、过滤器或另外一个服务中通过依赖声明的方式来使用服务。AngularJS 会像平时一样在运行期自动处理实例化和依赖加载的相关项。

1
2
3
4
angular.module("myApp")
.controller("myCtrl",function(myService){
myService.getName();
})

服务源码实现

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
function supportObject(delegate) {
return function(key, value) {
if (isObject(key)) {
forEach(key, reverseParams(delegate));
} else {
return delegate(key, value);
}
};
}
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 enforceReturnValue(name, factory) {
return function enforcedReturnValue() {
var result = instanceInjector.invoke(factory, this);
if (isUndefined(result)) {
throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
}
return result;
};
}
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
});
};
}

服务的工厂函数用来生成一个单例的对象或函数,这个对象或函数就是服务,它会存在于应用的整个生命周期中,当我们的AngularJS应用加载服务时,这个函数会被执行并返回一个单例的服务对象。

引用文章

  1. 《AngularJS 权威教程》 Ari Lerner
文章目录
  1. 1. 关于服务
  2. 2. 创建服务
    1. 2.1. factory()
    2. 2.2. service()
    3. 2.3. provider()
    4. 2.4. constant()与value()
    5. 2.5. decorator()
  3. 3. 使用服务
  4. 4. 服务源码实现
  5. 5. 引用文章