AngularJS服务
AngularJS提供了一些内置服务,在任何地方使用它们的方式都是统一的。同时,为复杂应用创建我们自己的服务也是非常有用的。
在AngularJS中创建自己的服务是非常容易的:只需要注册这个服务即可。服务被注册后,AngularJS编译器就可以引用它,并且在运行时把它当作依赖加载进来。服务名称的注册表使得在测试中伪造和剔除相互隔离的应用依赖变得非常容易。
注册一个服务
.factory("testFac",function(){ return{ getA:function(a){ return a; }, getB:function(b){ c(b) } } })
其中这个服务包含了2个方法,只需要在控制器中引用testFac就可以直接使用这2个方法,就可以了;这只是一次服务演示。当然,这2个方法是非常枯燥无味的;但是,假设你需要对用户信息进行验证,或者你需要读取用户的一些信息,那么这个服务就不枯燥无味了。
.factory("UserService",function($http){ var user_info; return{ getUserInfo:function(name,pwd){ $http({ url:"/login/?act=dologin", method:"POST", params:{r_type:"json"} }).success(function(data){ user_info = data.user_info; }) return user_info; }, getUser_name:function(){ return user_info.user_name; } } })
上面的代码我们稍微改了下,当引用getUserInfo这个方法的时候会直接发送服务器请求,获取用户数据,在设计网站时,这是非常实用的,我们可以把一些公共的数据,写成一个服务,然后在其他的控制器中直接引用数据就可以。
下面我们来使用服务
.controller("controllerMain",function($scope,$timeout,testFac,UserService){ c(testFac.getA("a")); testFac.getB("b"); })
需要在func中申明要引用的服务名称,然后我们直接引用它的方法即可;来试试UserService的服务:
.controller("controllerMain",function($scope,$timeout,testFac,UserService){ //c(testFac.getA("a")); //testFac.getB("b"); 为了方便演示,这里设置了一个按钮事件,当点击使用,我们读取用户数据 $scope.clickEvent = function(){ var a = UserService.getUserInfo("name","123456"); //假设,输入的用户名跟密码是正确的,那么这个a肯定就是一个用户数据的对象 console.log(a.user_name); console.log(UserService.getUser_name()) } })
创建服务时的设置项
在AngularJS应用中, factory() 方法是用来注册服务的最常规方式,同时还有其他一些API可以在特定情况下帮助我们减少代码量。
共有5种方法用来创建服务:
- factory()
如前所见, factory() 方法是创建和配置服务的最快捷方式。 factory() 函数可以接受两个参数。
name (字符串)
需要注册的服务名。
getFn (函数)
这个函数会在AngularJS创建服务实例时被调用。
.factory('testClass',function(){ return { getA:function(msg){ c(msg) }, getB:function(msg){ alert(msg) } } })
因为服务是单例对象, getFn 在应用的生命周期内只会被调用一次。同其他AngularJS的服务一样,在定义服务时, getFn 可以接受一个包含可被注入对象的数组或函数。
getFn 函数可以返回简单类型、函数乃至对象等任意类型的数据(同 value() 函数类似)。
angular.module('myApp') .factory('githubService', ['$http', function($http) { return { getUserEvents: function(username) { // ... } }; }]);
- service()
使用 service() 可以注册一个支持构造函数的服务,它允许我们为服务对象注册一个构造函数。
service() 方法接受两个参数。
name (字符串)
要注册的服务名称。
constructor (函数)
构造函数,我们调用它来实例化服务对象。
service() 函数会在创建实例时通过 new 关键字来实例化服务对象。
var service2 = function() { return { getA: function (msg) { c("service2:" + msg) }, getB: function (msg) { alert("service2:" + msg) } } };angular.module('myApp').service("myService2",service2)
- constant()
可以将一个已经存在的变量值注册为服务,并将其注入到应用的其他部分当中。例如,假设我们需要给后端服务一个 apiKey ,可以用 constant() 将其当作常量保存下来。
constant() 函数可以接受两个参数。
name (字符串)
需要注册的常量的名字。
value (常量)
需要注册的常量的值(值或者对象)。
constant() 方法返回一个注册后的服务实例。
angular.module(‘myApp’) .constant(‘apiKey’,’123123123′)
这个常量服务可以像其他服务一样被注入到配置函数中:
angular.module('myApp') .controller('MyController', function($scope, apiKey) { // 可以像上面一样用apiKey作为常量 // 用123123123作为字符串的值 $scope.apiKey = apiKey; });
- value()
如果服务的 $get 方法返回的是一个常量,那就没要必要定义一个包含复杂功能的完整服务,可以通过 value() 函数方便地注册服务。
value() 方法可以接受两个参数。
name (字符串)
同样是需要注册的服务名。
value (值)
将这个值将作为可以注入的实例返回。
value() 方法返回以 name 参数的值为名称的注册后的服务实例。
angular.module(‘myApp’)
.value(‘apiKey’,’123123123′);
value() 方法和 constant() 方法之间最主要的区别是,常量可以注入到配置函数中,而值不行。
通常情况下,可以通过 value() 来注册服务对象或函数,用 constant() 来配置数据。
angular.module('myApp', []) .constant('apiKey', '123123123') .config(function(apiKey) { // 在这里apiKey将被赋值为123123123 // 就像上面设置的那样 }) .value('FBid','231231231') .config(function(FBid) { // 这将抛出一个错误,未知的provider: FBid // 因为在config函数内部无法访问这个值 });
- provider()
所有服务工厂都是由 $provide 服务创建的, $provide 服务负责在运行时初始化这些提供者。提供者是一个具有 $get() 方法的对象, $injector 通过调用 $get 方法创建服务实例。$provider 提供了数个不同的API用于创建服务,每个方法都有各自的特殊用途。所有创建服务的方法都构建在 provider 方法之上。 provider() 方法负责在 $providerCache中注册服务。
从技术上说,当我们假定传入的函数就是 $get() 时, factory() 函数就是用 provider() 方法注册服务的简略形式。下面两种方法的作用完全一样,并且会创建同一个服务。
.factory('testClass',function(){ return { getA:function(msg){ c(msg) }, getB:function(msg){ alert(msg) } } }) // 这与上面工厂的用法等价 .provider('myService', { $get: function() { return { getA:function(msg){ c("myService:"+msg) }, getB:function(msg){ alert("myService:"+msg) } }; } })
是否可以一直使用 .factory() 方法来代替 .provider() 呢?
答案取决于是否需要用AngularJS的 .config() 函数来对 .provider() 方法返回的服务进行额外的扩展配置。同其他创建服务的方法不同, config() 方法可以被注入特殊的参数。
比如我们希望在应用启动前配置 githubService 的URL:
// 使用`.provider`注册该服务 angular.module('myApp', []) .provider('githubService', function($http) { // 默认的,私有状态 var githubUrl = 'https://github.com'; setGithubUrl: function(url) { // 通过.config改变默认属性 if (url) { githubUrl = url; } }, method: 'JSONP', // 如果需要,可以重写 $get: function($http) { self = this; return $http({ method: self.method, url: githubUrl + '/events'}); } });
通过使用 .provider() 方法,可以在多个应用使用同一个服务时获得更强的扩展性,特别是在不同应用或开源社区之间共享服务时。
在上面的例子中, provider() 方法在文本 githubService 后添加 Provider 生成了一个新的提供者githubServiceProvider 可以被注入到 config() 函数中。
angular.module('myApp', []) .config(function(githubServiceProvider) { githubServiceProvider.setGithubUrl("git@github.com"); });
如果希望在 config() 函数中可以对服务进行配置,必须用 provider() 来定义服务。
provider() 方法为服务注册提供者。可以接受两个参数。
name (字符串)
name 参数在 providerCache 中是注册的名字。 name + Provider 会成为服务的提供者。同时 name也是服务实例的名字。
例如,如果定义了一个 githubService ,那它的提供者就是 githubServiceProvider 。
aProvider (对象/函数/数组)
aProvider 可以是多种形式。
如果 aProvider 是函数,那么它会通过依赖注入被调用,并且负责通过 $get 方法返回一个对象。如果 aProvider 是数组,会被当做一个带有行内依赖注入声明的函数来处理。数组的最后一个元素应该是函数,可以返回一个带有 $get 方法的对象。如果 aProvider 是对象,它应该带有 $get 方法。provider() 函数返回一个已经注册的提供者实例。直接使用 provider() API是最原始的创建服务的方法:
// 在模块对象上直接创建provider的例子 angular.module('myApp', []) .provider('UserService', { favoriteColor: null, setFavoriteColor: function(newColor) { this.favoriteColor = newColor; }, // $get函数可以接受injectables $get: function($http) { return { 'name': 'Ari', getFavoriteColor: function() { return this.favoriteColor || 'unknown'; } }; } });
用这个方法创建服务,必须返回一个定义有 $get() 函数的对象,否则会导致错误。