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目录主 ...
随机推荐
- TCP协议学习笔记(一)首部以及TCP的三次握手连接四次挥手断开
TCP协议是一种面向连接的.可靠的流协议. 流即不间断的数据结构.这样能够保证接收到数据顺序与发送相同.但是犹如数据间没有间隔,因此在TCP通信中,发送端应用可以在自己所要发送的消息中设置一个标示长度 ...
- h5移动端常见问题
meta基础知识 H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 1 <meta name="viewport" content="width=device-w ...
- HTML标签marquee实现滚动效果
html标签 - <marquee></marquee>可以实现多种滚动效果,无需js控制.使用marquee标记不仅可以移动文字,也可以移动图片,表格等.只需要在<ma ...
- Selenium2学习-041-chromedriver:org.openqa.selenium.WebDriverException: unknown error: cannot determine loading status from unexpected alert open
今天在写WebDriver处理弹出框(alert.confirm.prompt)演示实例脚本分发给朋友时,在其执行时未能成功执行,对应的部分错误详情如下: org.openqa.selenium.We ...
- ACM集训的Day3 B。。。盲目搜索之DFS。。。
milk 一.题目描述: gzp有三个容量分别是A,B,C升的桶,A,B,C分别是三个从1到20的整数, 最初,A和B桶都是空的,而C桶是装满牛奶的.有时,农民把牛奶从一个桶倒到 另一个桶中,直到被灌 ...
- Renci.SshNet在Linux运维的应用
SSH.NET是一个.net的SSH应用库,支持并发.该库最新的代码可以从github上下载下来,比Sharp.SSH更新的频繁.它可以模拟ssh登陆,类似xshell.putty等工具.不过有更多的 ...
- awk sed 总结
Awk总结笔记 介绍 90年代 new awk :nawk Linux 的是gawk 我们简化awk 用法 # awk [options ] ‘scripts’ file1 file2 .... # ...
- php登陆与注册
登陆页面 <body><h1>登录页面</h1><form action="./dengluchuli.php" method=" ...
- jq弹框确认
function delCustomer(id,num){ var r=confirm("友情提醒:确认要删除客户吗?"); if (r==true){ $.ajax({ type ...
- iOS 如何在Label中显示html的文本
if (self.messageModel) { NSString * htmlString = self.messageModel.contentText; NSAttributedString * ...