angular源码阅读,依赖注入的原理:injector,provider,module之间的关系。
最开始使用angular的时候,总是觉得它的依赖注入方式非常神奇。
如果你跳槽的时候对新公司说,我曾经使用过angular,那他们肯定会问你angular的依赖注入原理是什么?
这篇博客其实是angular源码阅读之路的一个必经站点,就是要理解injector,provider,module之间的关系——这关系其实就是依赖注入的本质。
那么请专注地看下面这一段话吧:
通俗一点的理解:
module是发布任务的BOSS。
injector是领取任务的中间人。
provider是真正去执行任务的马仔。
当然上面这一段话只是比喻,不太严谨,可是很形象。待我慢慢解释来。
如果你比较熟悉angular,那么你肯定知道在每一个module对象上,都有一个私有属性"_invokeQueue"。
这个_invokeQueue,其实就是module发布的任务。
怎么理解『_invokeQueue,其实就是module发布的任务。』这句话呢?请看下面的简单小代码。
当我执行下面这段语句,我会在myapp中创建一个全局变量name='不咬人的蚊子':
//注册了一个全局变量name='不咬人的蚊子'
angular.module('myapp').constant('name','不咬人的蚊子');
而这个变量'name'我可以在controller里面这样使用:
angular.module.controller('myctr',['$scope','name',function($scope,name){
console.log(name)//不咬人的蚊子
$scope.name = name;
}])
现在说回_invokeQueue,当我执行了那个注册全局变量的constant方法的时候,其实是module发布了一个任务,这个任务保存在_invokeQueue里面。
注意:其实这时候只是发布任务,任务并没有被执行。这时候_invokeQueue里面是这样的:
module._invokeQueue=[
['constant',['name','不咬人的蚊子']]//数组里面包含着另一个数组。
]
对,没错,这就是Module发布的任务,invokeQueue其实就是一个数组,里面有着一系列任务(这里只是拿constant举例,其实在真实案例中,还会有各种任务,比如controller啊什么的)。
invokeQueue这个数组里面的每一个元素都是一个任务,如你所见,这任务也是一个数组。
任务数组的第1个元素(下标为0)记录了这个任务具体是什么任务,是constant,还是controller,还是directive等等。
任务数组的第2个元素(下标为1)记录了执行任务需要的参数。
注意注意,这里我们为了易于理解,只拿constant举例子,以后慢慢复杂起来,会越来越丰富。
注意注意,module发布了任务以后,只是发布了,并没有执行。
那么什么时候执行呢?
当angular一个app启动的时候,会自动生成一个injector,也就是大家口中的注射器,这是一个对象,这个injector对象会读取module中的各种任务。
比如injecotr读取module的invokeQueue之后,发现了第一条任务:
['constant',['name','不咬人的蚊子']]
于是injector就会发现,这是一个constant任务,参数是name,'不咬人的蚊子'。
injector并不能处理constant任务,所以它去找一个名为constant的provider,这个provider可以提供一个函数,这个函数正好接收两个参数。
于是injector把任务中的两个参数(也就是name和'不咬人的蚊子'这两个参数)交给constantProvider,让它来执行。
好了,这就是一个口头能讲明白的原理。那么angularJs是如何实现这个机制的呢?我打算把简单版的代码贴在下面,如果感兴趣的同学可以看看,如果不感兴趣的同学其实只要把上面的文字给看明白了,下面的代码随便看个乐呵就行。(这个代码可能会有部分是接着上一篇博客的代码,如果看着不知道怎么回事,可以看看上一篇博客。)
setupModuleLoader.js
function setupModuleLoader(window){
var ensure=function(obj,name,factory){
return obj[name]||(obj[name]=factory())
}
var angular = ensure(window,'angular',Object); var createModule = function(name,requires){
var invokeQueue=[];//增加一个任务队列
var moduleInstance = {
name:name,
requires:requires,
_invokeQueue:invokeQueue,
//constant方法的实质是向invokeQueue数组里面增加一个任务
constant:function(key,value){
invokeQueue.push(['constant',[key,value]])
},
};
return moduleInstance;
} ensure(angular,'module',function(){
var modules={};
return function(name,requires){
if(requires){
return createModule(name,requires,modules)
}else{
return getModule(name,modules);
}
}
})
}
createInjector.js
//createInjector(['app1','app2'])
//参数是一个字符串或者一个数组,内容是module名
function createInjector(modulesToLoad){
//cache用来缓存一些一直可以用到的值
var cache={}; $provide={
constant:function(key,value){
cache[key]=value;
}
} //这里的foreach方法并不是一个真正能运行的foreach,能看懂就行了
//每次APP启动的时候,injector都会按照传入的module名来遍历所有module
//这样就可以得到所有module发布的任务,并且一一执行这些任务
$.forEach(modulesToLoad,function(moduleName){
var module = window.angular.module(moduleName);
$.forEach(module._invokeQueue,function(invokeArgs){
var method=invokeArgs[0];
var args = invokeArgs[1];
$provide[method].apply($provide,args);
})
})
return {
has:function(key){
return cache.hasOwnProperty(key)
},
get:function(key){
return cache[key]
}
}
}
如果你耐着性子看到了这里,并且思路还算清晰,那么你肯定会问,现在injector执行了所有任务,并且把一切东西都准备好了,那么我们使用这些数据的途径和方法是什么呢?哈哈,这个别急,很快会解释明白,但是现在起码我们对依赖注入有了一个很好的理解了不是么?冬天来了,春天不会远了。
angular源码阅读,依赖注入的原理:injector,provider,module之间的关系。的更多相关文章
- Spring源码剖析依赖注入实现
Spring源码剖析——依赖注入实现原理 2016年08月06日 09:35:00 阅读数:31760 标签: spring源码bean依赖注入 更多 个人分类: Java 版权声明:本文为博主原 ...
- angular源码阅读的起点,setupModuleLoader方法
angular源码其实结构非常清晰,划分的有条有理的,大概就是这样子: (function(window,document,jquery,undefined){ //一些工具函数 //EXPR 编译器 ...
- angular源码阅读3:真的,依赖注入的原理
前面已经提到了: 如何注册一个module. 如何获取一个module. injector与module以及provider的关系. 那么已经剩下最后一部分了,就是关于依赖是如何被注入的. 且看下面这 ...
- Yii2.0源码阅读-behavior的实现原理
Yii2.0中的一个思想就是组件化的思想,所以.大多数的类都直接或间接的继承自yii\base\Component,而组件的三大功能:属性.事件.行为. 行为的目的是为了方便的扩展一个类的功能,而不需 ...
- ovs源码阅读--流表查询原理
背景 在ovs交换机中,报文的处理流程可以划分为一下三个步骤:协议解析,表项查找和动作执行,其中最耗时的步骤在于表项查找,往往一个流表中有数目巨大的表项,如何根据数据报文的信息快速的查找到对应的流表项 ...
- angular源码分析:angular中的依赖注入式如何实现的
一.准备 angular的源码一份,我这里使用的是v1.4.7.源码的获取,请参考我另一篇博文:angular源码分析:angular源代码的获取与编译环境安装 二.什么是依赖注入 据我所知,依赖注入 ...
- angular源码分析:injector.js文件分析——angular中的依赖注入式如何实现的(续)
昨天晚上写完angular源码分析:angular中jqLite的实现--你可以丢掉jQuery了,给今天定了一个题angular源码分析:injector.js文件,以及angular的加载流程,但 ...
- Kubernetes 学习(八)Kubernetes 源码阅读之初级篇------源码及依赖下载
0. 前言 阅读了一段时间 Golang 开源代码,准备正式阅读 Kubernetes 项目代码(工作机 Golang 版本为 Go 1.12) 参照 <k8s 源码阅读> 选择 1.13 ...
- python3 源码阅读-虚拟机运行原理
阅读源码版本python 3.8.3 参考书籍<<Python源码剖析>> 参考书籍<<Python学习手册 第4版>> 官网文档目录介绍 Doc目录主 ...
随机推荐
- Ubuntu 14.04 编译安装 boost 1.58
简介 Boost is a set of libraries for the C++ programming language that provide support for tasks and s ...
- find命令的拾遗
find -maxdepth 1 -regextype posix-extended -type f -regex "\./${name}[-\.].*\.(gz|bz2|tgz|zip|t ...
- Java提高篇——Java 异常处理
异常的概念 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的. 比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error:如果你用Syst ...
- python gevent 协程
简介 没有切换开销.因为子程序切换不是线程切换,而是由程序自身控制,没有线程切换的开销,因此执行效率高, 不需要锁机制.因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断 ...
- lua table integer index 特性
table.maxn (table) Returns the largest positive numerical index of the given table, or zero if the t ...
- 把 MWeb Lite 的文档库文档和数据搬到 MWeb 正式版中
MWeb Lite 版的文档库中的文档要搬到 MWeb 正式版中,如果 Lite 版的文档中没有图片或者只有少量图片,可以用导入导出为 Markdown 的方法. 否则的话请用以下方式(注意下面这个方 ...
- python爬虫
预:网页的组成 HTML(结构)+css(样式)+javascript(功能) 爬虫主要针对的是HTML和css HTML: <div></div>div标签 代表网页中某个区 ...
- Node.js Express 框架 POST方法
POST 方法 以下实例演示了在表单中通过 POST 方法提交两个参数,我们可以使用 server.js 文件内的 process_post 路由器来处理输入: index.htm 文件代码修改如下: ...
- Jquery插件Ztree使用所遇问题
问题1.$.fn.zTree为空或为Undefined 我在MVC中引用Jquery插件Ztree的JS并不存任何问题,而当我将Ztree的js引入项目中,就出现$.fn.zTree为空或为Undef ...
- IFRAM随内部长宽高变化
<iframe src="" id="iframe_CustomerVisitRecord" width="700" height=& ...