共计 4632 个字符,预计需要花费 12 分钟才能阅读完成。
一、为什么要使用服务
视图同$scope绑定在一起,而控制器管理数据。出于内存占用和性能的考虑,控制器只会在需要时被实例化,并且不再需要就会被销毁。这意味着每次切换路由或者重新加载视图时,当前的控制器会被angularJS清理掉。
服务提供了一种能在应用的整个生命周期内保持数据的方法,它能够在控制器之间进行通信,并且能保证数据的一致性。服务是一个单例对象,在每个应用中只会被实例化一次(被$injector实例化),并且是延迟加载的(需要时才会创建),服务提供了把与特定功能相关联的方法集中在一起的接口。
二、注册一个服务
创建服务的方法有共有5种:
- factory(),这是最常见也是最灵活的方式。
factory()函数接受两个参数,第一个name(这是一个字符串,表示服务的名字),第二个function(这个函数在angularJS创建服务实例时会被调用)angular.module('myApp.services',[]).factory('scervicesName',[function(){ return { //例如返回的对象有如下方法。这个返回的对象就是服务。 //有时这个返回也可以是一个函数,简单类型等任意类型的数据。 nameVlue:'hello word', gerFn:function(){}, setFn:function(){}, ... } }])
服务的工厂函数用来生成一个单例对象或函数。这个对象或者函数就是服务,它会存在于应用的整个生命周期内。
- service()可以注册一个支持构造函数的服务
sercive()方法接受两个参数,第一个name(这是一个字符串,表示服务的名字),第二个constructor(这个一个构造函数,在angularJS创建服务实例时会被调用)angular.service('peopleName',['$http',function($http){//$http这是一个内置的服务, this.getname = function(){ return $http({method:'GET',url:'/user'}) } }])
- porvider()
所有的服务工厂都是由$pervider服务创建的,$porvider服务负责在运行时初始化这些提供者。
提供者是一个具有$get()方法的对象,$injector通过调用$get方法创建服务实例。$provider提供了数个不同的API用于创建服务,每个方法都有不同的用途。
其他4个方法都是基于porvider方法创建的。porvider()方法负责在$porviderCache中注册服务。比如下面另个方法作用完全一样。angular.module('myApp.services',[]) .factory('scervicesName',[function(){ return { nameVlue:'hello word' } }]) .provider('scervicesName',{ $get:function(){ return { nameVlue:'hello word' } } })
如果需要对porvider()方法的服务进行额外的扩展配置。例如:
angular.module('myApp.services',[]) .provider('gitHubService',['$http',function($http){ var githubUrl = 'www.github.com' setUrl:function(url){ if(url){githubUrl =url } }, method:'JSONP', $get:function(){ self = this, return $http({method:self.method,url:githubUrl+'/user'}) } }])
然后在需要调用的地方。用config()方法注入特殊的参数。
angular.module('myApp.services',[]) .config(function(gitHubServicePorvider){ gitHubServicePorvider.setUrl('www.baidu.com'); })
porvider()方法为服务注册提供者,可以接受两个参数;第一个name(这是一个字符串,表示服务的名字),第二个aPorvider(对象/函数/数组);
当aPorvider是函数,那么它会通过依赖注入被调用,并且负责通过$get方法返回一个对象。
当aPorvider是数组,那么它会被当做一个带有行内依赖注入声明的函数来处理,数组的最后一个元素必须是对象,可以返回一个带有$get方法的对象。
当aPorvider是对象,那么它应该带有$get方法。angular.module('myapp',[]) .provider('UserService',{ name:'zzr', setName:function(new){ if(new){this.name=new} }, $get:function(){ return { 'name':'ari', getF:function(){ return this.name || "unknown" } } } })
如果你要实例化服务(一般的angularJS会自动处理服务的实例化,很少自己动手),可以使用$injector.
var injector = angular.injector(['myapp']); injector.invoke(['UserService',function(UserService){ //... }])
- constant(),可以将一个已经存在的变量值注册为服务,并将其注入到应用的其他部分当中。可用于指令或者控制器之间传递的常量!
constant()函数接受两个参数,第一个name(这是一个字符串,表示服务的名字),第二个value(常量)需要注册的常量的值或者对象。该方法返回一个注册后的服务实例。例如angular.module('myapp').constant("key","123123123"); angular.module('myapp').controller('myCtrl',function($scope,key){ $scope.key = key; })
- value(),如果$get方法返回的是一个常量,那么可以直接使用value()函数方便的注册服务。
value()函数接受两个参数,第一个name(这是一个字符串,表示服务的名字),第二个value(常量),将这个值将作为可以注入的实例返回。angular.module('myapp').value("key","123123123");
value()和constant()的区别,常量可以注入到配置的函数中,而值不行。通常value()来注册服务对象或函数,用constant()来配置数据
angular.module('myapp',[]) .constant("key1","123123131") .config(function(key1){ //这里key1将会被赋值为123123131 }) .value("key","lalala") .config(function(key){ //这里将抛出一个错误,因为这里无法访问key。 })
- decorator()(翻译为装饰器),$provide服务提供了在服务实例创建时对其进行拦截的功能,可以对服务进行扩展,或者用另外的内容完全代替它。ng的很多功能都是借助$provide.decorator()建立的。对服务进行装饰的场景有很多,比如对服务进行扩展,将外部数据缓存进localStorage的功能等等。
decorator()函数接受两个参数,第一个name(这是一个字符串,表示服务的名字),第二个function,这个函数由injector.invoke调用。可以将服务注入这个函数中,
$delegate是可以进行装饰的最原始的服务,为了装饰其他服务,需要将其注入进装饰器。
例如:下面代码展示了如何给Service添加装饰器,从而为每个请求都加上一个时间戳。angular.module('myapp',[]) .config(function($provide){ $provide.decorator('Service',function($delegate,$log){ return { events:function(path){ var startedAt = new Date(); var events = $delegate.events(path); events.finally(function(){ $log.info('Fetching took ' + (new Date() - startedAt) + 'ms') }) return events; } } }) })
三、使用服务
可以在控制器,指令,过滤器,或另外的一个服务中通过依赖注入的方式使用服务。将服务的名字当做参数传递给控制器函数,可以将服务注入到控制器中,当服务成为了某个控制器的依赖,就可以在控制器中调用任何定义在这个服务对象的方法。
angular.module('myapp',['myapp.services'])
.controller('serviceCtrl',function('$scope','githubService'){
//依赖注入的规则是内置的服务在前,之后在写自定义的服务
//这里可以使用githubService上的任何方法。
//使用起来就是这么简单
})
如果我们的应用中一个用来设置GITHUB用户名的设置页面,我们希望在应用中所有的控制器之间共享用户名。为了在控制器之间共享数据,需要在服务中添加一个用来储存用户名的方法。记住,服务在应用的生命周期内是单利模式的,因此可以将用户名安全地储存在其中。
angular.module('myapp.services',[])
.factory('githubService',function($http){
var gitUrl = 'http://github.com',getName;
var runUserRequest = function(path){
return $http({
method:"JSONP",
url:gitUrl +'/users/' + getName +'/'+path+'?callback=JSON_callback'
});
}
return {
events:function(){
return runUserRequest('events');
},
setUsername : function(username){
getName = username;
}
}
})
//-----------------------------------------
// githubService可以注入到任何一个控制器中,并可以在控制中调用events方法;
angular.module('myapp',['myapp.services'])
.controller('ServiceCtrl',function($scope,githubService){
$scope.setUsername = githubService.setUsername;
})