本篇文章参考自AngularJS权威教程。
1.简介
服务提供了一种能在应用的整个生命周期内保持数据的方法,它能在控制器之间进行通信,并且能保证数据的一致性。
服务是一个单例对象,在每个应用中只会被实例化一次,即被$injector实例化,并且是延迟加载的,服务提供了把与特定功能相关联的方法集中在一起的接口。
2.注册一个服务
使用angluar.module的factory API来创建服务是最常见最灵活的方式。
angular.module('myApp',[])
.factory('myService',function() {
return {
firstFunction:function() {
//doSomething
},
SecondFunction:function() {
//doSomething
}
};
如上,我们注册了一个名为myService的服务,factory方法第一个参数是注册的服务名,第二个参数一个函数,AngularJS创建该服务实例时,就会调用该函数返回的一个对象(服务是单例对象,故整个生命周期该函数只会被调用一次)。该函数也能注入其他服务,在写法上,一般把所有内置服务写在前面。例如,当我使用myService的时候,我就得到了一个拥有firstFunction,secondFunction两个函数的对象。只需要简单的用myService.firstFucntion()即可。
3.不同的注册方式
共有五种不同的方法可以注册服务,它们分别在特定的情况下使用。
1) factory()
如前所见,factory()方法是创建和配置服务的最快捷方式。factory()函数可以接受两个参数,一个声明服务名的字符串和一个仅会被调用一次用来获取服务对象实例的函数。
2) service()
使用service()与factory只有一点区别,就是它的第二个参数就是服务对象实例的构造函数。注意,该构造函数除了注入其他服务以外不能有任何参数,正因为此服务才是单例对象。下面例子中两种写法是一样的,factory中的函数要return一个对象,而service中的函数要用this来构造一个对象。
var Person = function($http) {
this.getName = function() {
return $http({method:"GET",url:"/api/user"});
}
this.defaultName = "奥巴马";
};
app.service(‘personService’,Person);
app.factory('personService',function($http) {
return {
getName:function() {
return $http({method:"GET",url:"/api/user"});
},
defaultName:"奥巴马"
}
}
3) provider()
provider()是最复杂也是最重要的方法,所有的服务创建最终都是由provider方法形成的。另外,如果希望能够在config()中进行配置,必须用provider()来定义服务以产生服务的provider对象,将此参数注入到config()中才可配置。
provider()负责在$providerCache中注册服务。所有服务工厂都是由$provide服务创建的,$provide服务负责在运行时初始化这些提供者。提供者是一个具有$get方法的对象,$injector通过调用这些提供者的$get方法创建服务实例。
provider()方法为服务注册提供者,可以接受两个参数。第一个参数name是字符串,它是服务实例的名字,name+”Provider”会自动称为服务的提供者。例如定义了一个myService,那么它的提供者就会是myServiceProvider。第二个参数是aProvider,有三种形式。无论哪种形式,其关键都在于$get方法,该方法会返回服务实例对象。
- 函数
如果该参数是函数,那么它是一个构造函数,它带有$get方法。 - 数组
如果该参数是数组,那么是一个行内注入声明,数组前面的是依赖,最后是一个函数,返回一个带有$get方法的对象。 - 对象
如果该参数是对象,那么它带有$get方法。
注意,带有$get方法的对象即是我们所说的服务的Provider对象,它的其他方法及属性就是我们能够对$get方法返回的服务实例对象进行配置的关键。
下面是一个使用provider()注册服务,并在config()中对其进行配置的例子。myService服务是从本地服务器取数据,url是从config()函数中通过myServiceProvider的setUrl方法配置的。
<body ng-app="myApp" ng-controller="myController">
<ul>
<li ng-repeat="name in names">
{{ name }}
</li>
</ul>
<script>
var app = angular.module("myApp",['ionic']);
app.config(function(myServiceProvider) {
myServiceProvider.setUrl("http://localhost:3000/person")
});
app.provider("myService",{
myUrl:null,
setUrl:function(url) {
myUrl = url;
},
$get:function($http) {
return {
getPerson:function() {
return $http({
method:"GET",
url:myUrl
});
}
}
}
});
app.controller("myController",function($scope,myService){
var promise = myService.getPerson();
promise.then(function(response) {
$scope.names = response.data;
});
});
</script>
</body>
上面的例子provider方法第二个参数是运用到了对象的写法,下面是该服务的另外两种写法,注意依赖注入是写在$get方法中。
app.provider("myService",function(){
this.myUrl = null;
this.setUrl = function(url) {
myUrl = url;
};
this.$get = function($http) {
return {
getPerson:function() {
return $http({
method:"GET",
url:myUrl
});
}
}
}
});
4) constant()
constant方法是用来注册常量(值和对象)用的,该服务实例对象就是常量值或常量对象本身。
constant可以接受两个参数,第一个参数是要注册的常量的名字,第二个是需要注册的常量值或者对象。constant注册的常量可以注入到config()中。
5) value()
同样是用来注册常量(值或对象)用的,参数与constant()相同,但它不能注入到config()中。另外value可以修改,而constant不可以修改,这里的修改指的是使用decorator(),即装饰器。
4.装饰器
$provider服务提供了在服务实例创建时对其进行拦截的功能,可以对服务进行拓展,甚至用另外的内容完全替代它。
装饰器强大的地方在于,它不仅可以应用在我们自己的服务上,也可以应用在AnuglarJS核心服务上,我们可以对AngularJS核心服务进行拦截、中断甚至替换功能的操作。我们在配置块中注入$provide,即可使用$provide的decorator方法进行装饰,decorator第一个参数是我们要装饰的服务名字,第二个参数则是一个函数,其参数$delegate就是原始服务对象,我们可以对$delegate修改并返回,甚至可以直接返回一个与原始服务对象$delegate完全无关的对象。返回的对象即是新服务的内容。
下面分别对factory()和value()方法注册的服务进行装饰。第一个例子是为factory()创建的服务添加一个方法,第二个例子是修改value的值。第三个例子直接将服务替换。
<body ng-app="myApp" ng-controller="myController">
<script>
var app = angular.module("myApp",['ionic']);
app.config(function($provide) {
$provide.decorator('myService',function($delegate) {
$delegate.log_second = function() {
console.log("second");
};
return $delegate;
});
});
app.factory("myService",function() {
return {
log_first:function() {
console.log("first");
}
}
});
app.controller("myController",function($scope,myService){
myService.log_first();
myService.log_second();
});
</script>
</body>
<body ng-app="myApp" ng-controller="myController">
<script>
var app = angular.module("myApp",['ionic']);
app.config(function($provide) {
$provide.decorator('key',function($delegate) {
$delegate = "654321";
return $delegate;
});
});
app.value("key","123456");
app.controller("myController",function($scope,key){
console.log(key);
});
</script>
</body>
<body ng-app="myApp" ng-controller="myController">
<script>
var app = angular.module("myApp",['ionic']);
app.config(function($provide) {
$provide.decorator('key',function($delegate) {
return {
log_first:function() {
console.log("first");
}
}
});
});
app.value("key","123456");
app.controller("myController",function($scope,key){
key.log_first();
});
</script>
</body>