AngularJS给我们提供了很多内置的服务,比如 $http, $log 等,我们也可以自定义服务,有几种方式自定义服务:factory
, service
, provider
一.什么是Service
服务的特点是什么:
- 最终目的就是可重用性
- 一个能在不同控制器中使用的特别的代码单元
- 服务可以当作工具或者业务逻辑单元
-
服务是
单例
,只被实例化一次,然后一直保存在Angular应用中。而controllers则是需要使用时被构造,不需要时被销毁 - 只有一个控制器注入服务时,服务才被实例化,懒加载
- 控制器可以同时使用多个服务
-
一个服务也可以注入其它服务
#1service.jpg
二.创建自定义服务
创建服务有3中方式, factory
, service
, provider
:
- 其中
factory
,service
只是写法上有些微差异,下面会详细介绍语法 -
factory
,service
其实是provider
的语法糖 -
provider
可以在服务实例化之前提供一些配置参数(配置阶段
),在配置阶段不能使用服务,这点需要注意 -
provider
必须返回一个this.$get
函数,这个函数就相当于factory
下面具体来看这3种方式的语法
1.Factory
语法:
app.factory(factoryName, [DI, function(DI) { // 注入其它的服务
// 定义一个对象
var oService = {};
// 定义对象上的属性方法
oService.getSum = function() {}
...
// 将这个对象返回
return oService
}])
#2service-factory.jpg
示例:
// html
<div ng-controller="sample">
a: {{a}} <input ng-model="a" /> <br/>
b: {{b}} <input ng-model="b" /> <br/>
sum = {{sum}}
<button ng-click="getSum()">总和</button>
</div>
// js
app.controller('sample', ['calcFactory', function(calcFactory) { // 使用该服务
$scope.a = 0;
$scope.b = 0;
$scope.sum = 0;
$scope.getSum = function() {
$scope.sum = calcFactory.addSum($scope.a, $scope.b); // 调用factory上的方法
}
}])
// 定义factory
app.factory('calcFactory', ['$log', function($log) {
var oCalcService = {}; // 定义一个对象
// 对象上的属性方法 同步方法
oCalcService.addSum = function(a, b) {
return parseInt(a, 10) + parseInt(b, 10);
}
// 其它的一些方法属性
// 返回该对象
return oCalcService;
}])
上面我们在服务中定义的方法使用的是同步方法,我们可以使用异步的方式来处理,这种方式也比较常见
// js
app.controller('sample', ['calcFactory', function(calcFactory) { // 使用该服务
$scope.a = 0;
$scope.b = 0;
$scope.sum = 0;
$scope.getSum = function() {
calcFactory.addSum($scope.a, $scope.b, function(r) {
$scope.sum = r; // 这里简单的将结果赋给$scope.sum
}); // 第3个参数为回调函数,可以自定义逻辑
}
}])
// 定义factory
app.factory('calcFactory', ['$log', function($log) {
var oCalcService = {};
// 对象上的属性方法 异步方法
// 第3个参数为一个回调函数,逻辑由控制器决定
oCalcService.addSum = function(a, b, cb) {
var r = parseInt(a, 10) + parseInt(b, 10);
cb(r);
}
return oCalcService;
}])
另外假设我们的计算过程是在服务端完成的,这时我们需要使用 $http
服务
// 定义factory
app.factory('calcFactory', ['$log', '$http', function($log, $http) { // 使用'$http'服务
var oCalcService = {};
oCalcService.addSum = function(a, b, cb) {
// 在服务端计算
// 假设服务端地址为'http://localhost:8888/Sum?a=10&b=20'(10, 20)为传入的参数
$http({
url: 'http://localhost:8888/Sum?a=' + a + '&b=' + b,
method: 'GET'
}, function(res) {
cb(res.data); // 获取结果,传给回调函数
}, function(err) {
$log.log(err); // 错误处理
})
}
return oCalcService;
}])
2.Service
这个和Factory并没有什么差异,只是写法的不同,它会跟一个构造函数,这个构造函数会被AngularJS 自动
实例化
语法:
// 后面是构造函数,可以直接使用'this'
// 服务被调用时,Angular将自动的实例化这个构造器
app.service(serviceName, [DI, function(DI) {
this.addSum = function() {};
this.timeSUm = function();
// 其余逻辑
}])
#3service-service.jpg
示例(使用上面的例子):
app.controller('sample', ['calcService', function(calcService) { // 使用该服务
$scope.a = 0;
$scope.b = 0;
$scope.sum = 0;
$scope.getSum = function() {
$scope.sum = calcService.addSum($scope.a, $scope.b, function(r) {
$scope.sum = r;
}); // 调用calcService上的方法
}
}])
app.service('calcService', ['$log', function($log) {
this.addSum = function(a, b, cb) {
var s = parseInt(a) + parseInt(b);
cb(s);
}
}])
可以看出几乎和Factory的写法一致
3.Provider
这个写法和上面的有很大的差异,因为它可以添加 配置
, 这些配置参数可以在配置阶段使用,使用时需要注意的是,注入的服务需要添加在 this.$get
函数中,不能直接添加在provider函数中,因为配置阶段注入服务是访问不到的
语法:
app.provider(providerName, function() {
// 配置函数, 'config' 可以是别的变量名, 比如'this.settings'
// 下面的 'providerNameProvider.config(params)'会使用到
// 在服务被实例化之前被 'Provider' 执行
this.config = function(params) {}
// 实质是一个Factory
// 可以使用provider提供的配置信息
this.$get = [DI, function(DI) {
var someObj = {};
someObj.someMethod = function() {};
return someObj;
}]
})
// 给服务提供配置
// 在服务实例化之前提供配置信息
// 在配置阶段被执行
// 注意名字只能是服务名后面添加'Provider'
app.config[providerNameProvider, function(providerNameProvider) {
providerNameProvider.config(params)
}]
#4service-provider.jpg
示例, 假如我们上面服务端计算的url可以自己配置:
app.provider('calcService', function() {
var baseUrl = '';
this.settings = function(url) {
baseUrl = url;
}
this.$get = ['$log', '$http', function($log, $http) {
var oCalcObject = {};
oCalcObject.addSum = function(a, b, cb) {
$http({
url: baseUrl + '/Sum?a=' + a + '&b=' + b,
method: 'GET'
}).then(function(res) {
$log(res.data);
cb(res.data)
}, function(err) {
$log.log(err);
})
}
}]
})
// 配置
app.config('calcServiceProvider', function(calcServiceProvider) {
calcServiceProvider.settings('http://localhost: 8888')
})
可以看出provider和其它2种方式最大的不同就是,可以提供配置信息,这样写可以更灵活,不必写死。