AngularJS Source code
Angular.js
辅助函数
- lowercase
- hasOwnProperty
- uppercase
- mannualLowercase
- mannualUppercase
- isArrayLike
- forEach
- reverseParams
核心功能
angularInit(element, bootstrap)
找到带有ng-app的节点,读取module,在该节点上启动bootstrap。bootstrap(element, modules, config)
先往modules中加入“provide”, “ng”两个module,然后调用createInjector(modules, config.strictDi)创建一个injector,再之后如下:
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
});
}]
);
其实也就是手动调用了一个$scope的更新过程,所以重点在于createInjector和compile两个函数了。
auto/injector.js
辅助函数
- extractArgs(fn)
从javascript函数对象中把参数读出来,这个利用了javascript函数的toString()的方法会返回函数的定义的特点。 - anonFn(fn)
为一个函数取一个名字 - annotate(fn, strictDi, name)
为一个函数添加一个$inject对象,里面存入函数参数列表(?这个还不太确定)
核心函数
injector的主入口是createInjector(modulesToLoad, strictDi),解析这个函数需要一步一步的来:
首先我们必须对Injector的结构有一个透彻了解,参见函数createInternalInjector(cache, factory)。
createInternalInjector(cache, factory)
返回一个injector对象,其中各个属性如下:
* get(serviceName, caller)
试图从cache中取出service对象,否则则调用factory(serviceName, caller)并将结果存入cache.
* injectionArgs(fn, locals, serviceName)
fn获取其参数列表,然后按照locals[key], getService(key, serviceName)的优先级获取fn的参数返回。
* invoke(fn, self, locals, serviceName)
调用injectionArgs(fn, locals, serviceName)实例化arguments, 然后调用fn函数。
* instantiate(Type, locals, serviceName)
第一个Type是构造函数,同样调用injectionArgs(Type, locals, serviceName)实例化arguments,然后调用构造函数获取实例并且返回。injector的get方法会总是试图从cache中取出实例,当实例不存在时,调用factory方法处理。invoke和instantiate都是先从函数中获取参数列表,然后用locals和cache来实例化参数,然后调用函数获取结果。
新建了一个变量providerCache,作为所有provider的cache,同时该cache中预存了$provide对象,里面提供了以下方法:
- provider(name, provider_)
- factory(name, factoryFn, enforce)
- service(name, constructor)
- value(name, value)
- decorator(serviceName, decorFn)
除了最后的decorator,这一系列方法都是在providerCache中存入一个包含$get方法的provider。该方法会在各个模块的configProvider中使用,将provider存在providerCache中去。
利用刚刚的providerCache建立第一个injector: providerInjector, 其factory方法会报错提示provider不存在。
用一个空对象建立第二个injector: instanceInjector,不同的是它的factory方法,该方法总是先试图用providerInjector获取其provider,然后调用instanceInjector.invoke(provider.$get, provider, undefined, serviceName)。
在providerCache中加入$injector的provider,因此可以通过injector获取injector自身。
总结一下,injector基于某一个cache来进行实例的存取和函数参数的实例化,对于不存在的实例,各个injector处理方法不一样,providerInjector是会报错的,而intanceInjector会调用providerInjector首先获取provider,然后实例化instance,最后存入instanceCache中。
调用loadModules(modulesToLoad),最后使用instanceInjector来invoke返回的runBlocks。
loadModules的内容相对比较直接,阅读其源代码可知道主要做了以下三件事:
1. 加载该module require的modules
2. runInvokeQueue(module._invokeQueue)
2. runInvokeQueue(module._configBlocks)
3. 返回modules的_runBlocks
runInvokeQueue方法的代码如下:
function runInvokeQueue(queue) {
var i, ii;
for (i = 0, ii = queue.length; i < ii; i++) {
var invokeArgs = queue[i],
provider = providerInjector.get(invokeArgs[0]);
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
}
}
```
loader.js
可以通过阅读下setupModuleLoader的代码来了解angular的module机制。
首先需要了解函数invokeLater(provider, method, insertMethod, queue)和invokeLaterAndSetModuleName(provider, method),当insertMethod, queue都没有提供的时候,它返回匿名函数,该函数调用时将会在queue中inserMethod进[provider, method, arguments]的一个数组。该数组将会被injector调用。如上一章的code所示,它将会先取出provider,然后调用其method(arguments)。
这里我们看到module.provider的定义是invokeLaterAndSetModuleName('$provide', 'provider')
因此当我们调用angular.module(test).provider()时,它将会在该module的queue里存入相应的数据,之后在angular初始化时,它将会用providerInjector取出$provide服务,然后我们可以调用它里面的各种预存方法,从而将provider预存进providerCache。
AngularJS Source code的更多相关文章
- Tips for newbie to read source code
This post is first posted on my WeChat public account: GeekArtT Reading source code is always one bi ...
- 编程等宽字体Source Code Pro(转)
Source Code Pro - 最佳的免费编程字体之一!来自 Adobe 公司的开源等宽字体下载 每一位程序员都有一套自己喜爱的代码编辑器与编程字体,譬如我们之前就推荐过一款"神 ...
- How to build the Robotics Library from source code on Windows
The Robotics Library is an open source C++ library for robot kinematics, motion planning and control ...
- How to build windows azure PowerShell Source Code
Download any version source code of Windows Azure Powershell from https://github.com/Azure/azure-sdk ...
- akka cluster sharding source code 学习 (1/5) 替身模式
为了使一个项目支持集群,自己学习使用了 akka cluster 并在项目中实施了,从此,生活就变得有些痛苦.再配上 apache 做反向代理和负载均衡,debug 起来不要太酸爽.直到现在,我还对 ...
- view class source code with JAD plugin in Eclipse
The default class viewer doesn't decompile the class file so you cannot open and check the source co ...
- Classic Source Code Collected
收藏一些经典的源码,持续更新!!! 1.深度学习框架(Deep Learning Framework). A:Caffe (Convolutional Architecture for Fast Fe ...
- Attach source code to a Netbeans Library Wrapper Module
http://rubenlaguna.com/wp/2008/02/22/attach-source-code-to-a-netbeans-library-wrapper-module/ Attach ...
- convert source code files to pdf format in python
import os import sys def find_file(root_dir, type): dirs_pool = [root_dir] dest_pool = [] def scan_d ...
随机推荐
- xml html xhtml html5
1.XML 什么是 XML? XML 指可扩展标记语言(EXtensible Markup Language) XML 是一种标记语言,很类似 HTML XML 的设计宗旨是传输数据,而非显示数据 X ...
- 【BZOJ4675】点对游戏 树分治+期望
[BZOJ4675]点对游戏 Description 桑尼.露娜和斯塔在玩点对游戏,这个游戏在一棵节点数为n的树上进行. 桑尼.露娜和斯塔三人轮流从树上所有未被占有的节点中选取一点,归为己有,轮流顺序 ...
- 【BZOJ1511】[POI2006]OKR-Periods of Words next数组
[BZOJ1511][POI2006]OKR-Periods of Words Description 一个串是有限个小写字符的序列,特别的,一个空序列也可以是一个串. 一个串P是串A的前缀, 当且仅 ...
- luarocks错误 require ‘luasql.mysql' 报module 'luasql.mysql' not found:
错误: require 'luasql.mysql'stdin:1: module 'luasql.mysql' not found: no field package.preload['luasql ...
- 墨菲定律(Murphy's Law)
https://baike.baidu.com/item/墨菲定律/746284?fr=aladdin 墨菲定律是一种心理学效应,是由 爱德华·墨菲(Edward A. Murphy)提出的. 主要内 ...
- 手动拼写出来的sp_who结果集
SELECT SPID = er.session_id ,STATUS = ses.STATUS ,[Login] = ses.login_name ,Host = ses.host_name ...
- 对比MySQL,你究竟在什么时候更需要MongoDB(转)
译文:对比MySQL,你究竟在什么时候更需要MongoDB 原文链接: When Should I Use MongoDB rather than MySQL (or other RDBMS): Th ...
- Python 一键同步windows和linux数据(基于pscp.exe)
outline 项目中需要把 windows server 上的数据同步到 linux server,方法很多,这里记录下自己采用的一种比较简单的方法. 准备工作 首先确保你 windows serv ...
- 如何做好部门以及公司的文档管理、知识管理以及情报管理?——By Me
之前针对部门的文档管理开发平台进行过一次需求调研分析,对于实现方案与我们的实际需求之前的满足情况系统梳理了一下,我觉得对于有类似需求的团队或者公司应该有可以借鉴的地方,发到这里供大家参考.如有不正之处 ...
- docker安装升级linux内核(2.6.32->3.10.81)
.内核升级环境准备 #查看已经安装的和未安装的软件包组,来判断我们是否安装了相应的开发环境和开发库: yum grouplist #一般是安装这两个软件包组,这样做会确定你拥有编译时所需的一切工具 y ...