本文源自:http://blog.csdn.net/woxueliuyun/article/details/50962645
学习之后略有所得, 来此分享。建议看原文。
模块是提供一些特殊服务的功能块,比如本地化模块负责文字本地化,验证模块负责数据验证。一般来说,服务在模块内部,当我们需要某个服务的时候,是先把模块实例化,然后再调用模块的方法。但Angular模块和我们通常理解的模块不一样,Angular模块只保留服务的声明,服务的实例化是由服务注入器完成的,实例化之后服务就留在了服务注入器中,和模块没有关系了,这就是为什么我们使用的服务全部来自注入器的原因。
每调用一次angular.boostrap()方法会创建一个新的Angular应用和一个新的服务注入器,因此,每个应用都对应一个服务注入器,彼此互不冲突。
在angular中,模块可以是对象、方法(如果是数组,数组的最后一个元素必须是方法,前面的元素都是方法按顺序排列的参数名称)。后面讲的模块属性和方法,都属于通过angular.module()定义的模块对象。如果模块是方法,是不需要经过angular.module()定义的,只需写入依赖数组(就是说依赖数组的元素可以是方法),模块在加载依赖关系的时候直接执行了。
注意:通过angular.module()方法定义的模块是唯一的,如果重复定义就会覆盖前面的定义。
angular模块通过angular.module(name,requires, configFn)方法生成:
- 参数name是模块名称;
- 参数requires表示依赖模块数组。如果不设置requires参数,调用angular.module(name)方法表示获取这个模块;因此,如果确定新模块没有依赖关系,必须设置requires为空数组[];
- 参数configFn是方法或数组,负责在模块初始化时做一些配置,如果是数组,最后一个元素必须是方法。
方法configFn并不是在执行angular.module()的时候立即执行,而是当这个模块被第一次使用时,由注入器调用执行。同时,查看方法configFn中的this就会发现,这个this在浏览器中指向的是window,而不是module。而且,方法configFn只会执行一次,因此同一个angular模块不会重复配置。
参数requires中的字符串表示依赖的模块名称。如果不是字符串,则必须是方法(或数组格式的方法),那么,这个方法就代表了一个模块。
同名模块
已经初始化的angular模块保存在一个叫modules的缓存对象中,key是模块名,value是模块对象。所以,定义一个同名的模块,等于覆盖之前的模块。
服务注入
前面已经讲了,angular模块只保留服务的定义,现在我们再来理解服务是如何加入注入器的。
在了解服务注入器前,还需要了解另一个概念,就是服务提供商,在Angular中称为Provider,几乎所有的服务(除了$injector)都是由服务提供商供应。无论是服务还是服务提供商,他们在Angular中都是唯一的,服务和服务提供商是一个一对一的关系。也正是因为这个关系,我们在使用模块service()、value()等方法时,感觉我们定义的好像只是服务,但其实Angular背后为这些服务都创建了一一对应的服务提供商。注入器的机制就是当我们需要某个服务的时候,首先根据服务名找到对应的服务提供商,然后由服务提供商创建对应的服务并返回。
所以这就是整个过程:
- 模块定义服务、服务提供商;
- 注入器根据模块依赖关系加载模块,实例化所有服务提供商;
- 应用需要服务,注入器根据服务名寻找服务提供商,服务提供商实例化服务。
以上只是理论,现在从代码层面来看Angular是如何实现的。
每个angular模块内置有三个数组,invokeQueue保存如何注入服务提供商和值的信息;configBlocks保存模块的配置信息;runBlocks保存这个模块的执行信息。模块被使用的时候,注入器根据invokeQueue中的信息,实例化服务提供商;根据configBlocks中的信息对服务提供商做一些额外的处理;根据runBlocks中提供的信息,调用前面的服务提供商提供的服务执行模块需要完成的工作。
angular模块提供了很多方法来填充这三个数组,比如config()、run()等。三个数组的元素也是数组,具体元素格式参考后面的说明。
调用队列 – invokeQueue
数组元素为[‘provider’, ‘method’, arguments]。
举例– 添加一个Controller:
1 angular.module('ngAppDemo',[]) 2 3 .controller('ngAppDemoController',function($scope) { 4 5 $scope.a= 1; 6 7 $scope.b = 2; 8 9 });