AngularJS开发指南15:AngularJS的创建服务,将服务注入到控制器,管理服务依赖详解
创建服务
虽然AngularJS提供了很多有用的服务,但是如果你要创建一个很棒的应用,你可能还是要写自己的服务。你可以通过在模块中注册一个服务工厂函数,或者通过Module#factory api或者直接通过模块配置函数中的$provide api来实现。
所有的服务都符合依赖注入的原则。它们用一个唯一的名字将自己注册进AngularJS的依赖注入系统(injector),并且声明需要提供给工厂函数的依赖。它们的依赖在测试中可以是虚拟的,这使得它们能很好地被测试。
注册服务
要注册服务,你首先要有一个包含该服务的模块。然后你就能通过模块的api或者使用模块配置函数中的$provide服务来注册你的服务了。下面的伪代码显示了这两种方法。
使用angular.Module api:
var myModule = angular.module('myModule', []);
myModule.factory('serviceId', function() {
var shinyNewServiceInstance;
//factory function body that constructs shinyNewServiceInstance
return shinyNewServiceInstance;
});
使用$provide服务:
angular.module('myModule', [], function($provide) {
$provide.factory('serviceId', function() {
var shinyNewServiceInstance;
//factory function body that constructs shinyNewServiceInstance
return shinyNewServiceInstance;
});
});
注意,你不应该注册一个服务实例,而是一个会在被调用时创建实例的工厂函数。
依赖
服务不仅可以被依赖,还可以有自己的依赖。依赖可以在工厂函数的参数中指定。参阅AngularJS的依赖注入系统,和使用依赖的数组表示法和$inject属性来让依赖表示精简化。
下面是一个很简单的服务的例子。这个服务依赖于$window服务(会被当成参数传递给工厂函数),并且只是个函数。这个服务的任务是存储所有的通知;在第三个通知以后,服务会用window的alert来输出所有的通知。
angular.module('myModule', [], function($provide) {
$provide.factory('notify', ['$window', function(win) {
var msgs = [];
return function(msg) {
msgs.push(msg);
if (msgs.length == 3) {
win.alert(msgs.join("\n"));
msgs = [];
}
};
}]);
});
实例化AngularJS的服务
所有服务都是延迟实例化的。这意味着所有的服务只有在需要时,或者被依赖时才会实例化。换句话说,AngularJS不会实例化服务,除非被请求了或者被应用直接或间接依赖了。
要注意的是所有的AngularJS服务都是单例的。这意味着在每一个注入器中都只有一个需要的服务的实例。
将服务注入到控制器中
将服务用作控制器的依赖和将服务用作其他服务的依赖很类似。
显式依赖注入
因为Javascript是一种动态语言,依赖注入系统无法通过静态类型来知道应该注入什么样的服务(静态类型语言就可以)。所以,你应该用$inject的属性来指定服务的名字,这个属性是一个包含需要注入的服务的名字字符串的数组。名字要和服务注册到系统时的名字匹配。服务的名称的顺序也很重要:当执行工厂函数时传递的参数是依照数组里的顺序的。但是工厂函数中参数的名字不重要,但最好还是和服务本身的名字一样。举个例子:
angular.
module('MyServiceModule', []).
factory('notify', ['$window', function(win) { //定义了一个服务notify
var msgs = [];
return function(msg) {
msgs.push(msg);
if (msgs.length == 3) {
win.alert(msgs.join("\n"));
msgs = [];
}
};
}]); function myController(scope, notifyService) { //这里的scope是$scope,notifyService是notify服务
scope.callNotify = function(msg) {
notifyService(msg);
};
} myController.$inject = ['$scope','notify']; //显式定义依赖注入
隐式依赖注入
AngularJS依赖注入系统的新特性使得AngularJS可以通过参数名称来判断依赖。下面的例子展示一下隐式地依赖$window, $scope:
angular.
module('MyServiceModuleDI', []).
factory('notify', function($window) {
var msgs = [];
return function(msg) {
msgs.push(msg);
if (msgs.length == 3) {
$window.alert(msgs.join("\n"));
msgs = [];
}
};
}); function myController($scope, notify) { //通过参数名字,来隐式的定义依赖注入
$scope.callNotify = function(msg) {
notify(msg);
};
但是如果你要压缩你的代码,你的变量名会被重命名,所以这时你就只能显示地指定依赖了。
管理服务依赖
要声明服务的依赖,你可以在工厂方法参数中隐式指明他们,也可以将$inject属性设置成包含了依赖名称的数组,或者是使用数组表示法。不推荐使用$inject属性的这种方法。
使用数组表示法:
function myModuleCfgFn($provide) {
$provide.factory('myService', ['dep1', 'dep2', function(dep1, dep2) {}]); //依赖dep1,dep2服务
}
使用$inject属性:
function myModuleCfgFn($provide) {
var myServiceFactory = function(dep1, dep2) {};
myServiceFactory.$inject = ['dep1', 'dep2']; //依赖dep1,dep2服务
$provide.factory('myService', myServiceFactory);
}
使用隐式依赖(使用代码压缩时会失效):
function myModuleCfgFn($provide) {
$provide.factory('myService', function(dep1, dep2) {});
}
举个例子来说明下服务之间的依赖:
function batchLogModule($provide){
$provide.factory('batchLog', ['$timeout', '$log', function($timeout, $log) {
var messageQueue = [];
function log() {
if (messageQueue.length) {
$log('batchLog messages: ', messageQueue);
messageQueue = [];
}
$timeout(log, 50000);
}
log();
return function(message) {
messageQueue.push(message);
}
}]);
$provide.factory('routeTemplateMonitor',
['$route', 'batchLog', '$rootScope',
function($route, batchLog, $rootScope) {
$rootScope.$on('$routeChangeSuccess', function() {
batchLog($route.current ? $route.current.template : null);
});
}
]
);
}
angular.injector([batchLogModule]).get('routeTemplateMonitor');
上例中有几点要注意:
- batchLog服务依赖内建的$timeout和$log服务,并且允许消息批量地使用console.log记录。
- 和batchLog服务一样,routeTemplateMonitor服务依赖内建的$route服务。
- 自定义的服务都使用隐式表示和数组法来表示自己的依赖。最重要的是数组中的服务的名字顺序要和工厂函数参数的名字顺序对应。除非依赖是隐式地通过函数参数名表示的,那么就是有声明依赖的数组名称顺序决定依赖注入的顺序。
总结
AngularJS服务是一种能执行一个常见操作的单例,比如$http服务是用来操作浏览器的XMLHttpRequest对象的。
要使用AngularJS服务,你只需要在需要的地方(控制器,或其他服务)指出依赖就行了。AngularJS的依赖注入系统会帮你完成剩下的事情。它负责实例化,查找左右依赖,并且按照工厂函数要求的样子传递依赖。
AngularJS web框架提供了一组常用操作的服务。和其他的内建变量或者标识符一样,内建服务名称也总是以"$"开头。另外你也可以创建你自己的服务。
加油!
AngularJS开发指南15:AngularJS的创建服务,将服务注入到控制器,管理服务依赖详解的更多相关文章
- AngularJS开发指南3:Angular主要组成部分以及如何协同工作
AngularJS的主要组成部分是: 启动(startup) - 展示“hello world!” 执行期(runtime) - AngularJS 执行期概览 作用域(scope) - 视图和控制器 ...
- Qt开发技术:QCharts(三)QCharts样条曲线图介绍、Demo以及代码详解
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- Linux服务器,服务管理--systemctl命令详解,设置开机自启动
Linux服务器,服务管理--systemctl命令详解,设置开机自启动 syetemclt就是service和chkconfig这两个命令的整合,在CentOS 7就开始被使用了. 摘要: syst ...
- Linux服务管理 systemctl命令详解
Linux服务器,服务管理--systemctl命令详解,设置开机自启动 syetemclt就是service和chkconfig这两个命令的整合 任务 旧指令 新指令 使某服务自动启动 ch ...
- AngularJS开发指南14:AngularJS的服务详解
服务是一种由服务器端带到客户端的特性,它由来已久.AngularJS应用中的服务是一些用依赖注入捆绑在一起的可替换的对象.服务是最常和依赖注入一起用的,它也是AngularJS中的关键特性. 接下来, ...
- AngularJS开发指南16:AngularJS构建大型Web应用详解
AngularJS是由Google创建的一种JS框架,使用它可以扩展应用程序中的HTML功能,从而在web应用程序中使用HTML声明动态内容.在该团队工作的软件工程师Brian Ford近日撰写了一篇 ...
- AngularJS开发指南8:AngularJS模块的详解
在讲angularjs的模块之前,我们先介绍一下angular的一些知识点: AngularJS是纯客户端技术,完全用Javascript编写的.它使用的是网页开发的常规技术(HTML,CSS,Jav ...
- AngularJS开发指南11:AngularJS的model,controller,view详解
model model这个词在AngularJS中,既可以表示一个(比如,一个叫做phones的model,它的值是一个包含多个phone的数组)对象,也可以表示应用中的整个数据模型,这取决于我们所讨 ...
- AngularJS开发指南10:AngularJS依赖注入的详解
依赖注入是一种软件设计模式,用来处理代码的依赖关系. 一般来说有三种方法让函数获得它需要的依赖: 它的依赖是能被创建的,一般用new操作符就行. 能够通过全局变量查找依赖. 依赖能在需要时被导入. 前 ...
随机推荐
- Same Tree
Given two binary trees, write a function to check if they are equal or not. Two binary trees are con ...
- WCF并发控制与实例模式
WCF实例模式类型与区别 实例化模式 instanceMode percall 单调模式 [ServiceBehavior(InstanceContextMode=InstanceCon ...
- Centos7 搭建hadoop2.6 HA
用户配置: User :root Password:toor 2.创建新用户 student Pwd: student 3.安装virtualbox的增强工具软件 4.系统默认安装的是openjdk ...
- Java dynamical proxy demo
今天练习了一下动态代理的一个方面,假设使用它来完成自动设置默认不提交,启动事务,获取到异常则回滚,正常执行则提交. 如果不使用动态代理,则需要在每个方法本身里面设置Connection,写try,ca ...
- web工程 所需是jar包总结
commons-beanutils-1.8.3.jar : BeanUtils主要提供了对于JavaBean进行各种操作,需要Commons -Collections包和Commons -loggin ...
- hihocoder-1389&&2016北京网赛07 Sewage Treatment(二分+网络流)
题目链接: Sewage Treatment 时间限制:2000ms 单点时限:2000ms 内存限制:256MB 描述 After years of suffering, people could ...
- ajax请求json数据案例
今天有这样一个需求,点击六个大洲,出现对应的一些请求信息,展示在下面,请求请求过后,第二次点击就无需请求.如图所示:点击北美洲下面出现请求的一些数据 html代码结构: <div class=& ...
- ZOJ 2301 / HDU 1199 Color the Ball 离散化+线段树区间连续最大和
题意:给你n个球排成一行,初始都为黑色,现在给一些操作(L,R,color),给[L,R]区间内的求染上颜色color,'w'为白,'b'为黑.问最后最长的白色区间的起点和终点的位置. 解法:先离散化 ...
- MATLAB基本命令
eye(n)创建n阶单位矩阵 zeros(n)创建n阶0方阵 rand(m,n)创建m*n阶元素为从0到1的均匀分布的随机数矩阵 round(A)对矩阵A中所有元素进行四舍五入运算 A^-1用幂运算求 ...
- 最长公共子序列模板(LCS)和LICS模板
递归式: 实例图解: 代码: #include<stdio.h> #include<string.h> ; int dp[N][N],f[N][N]; char a[N],b[ ...