和几年前相比,现在的Javascript开发方式有了翻天覆地的变化,一些极具创意的开发工具的出现,让前端开发更加成熟,Angular框架就是一个例子。最近在看Angular的源代码,发现并不是件容易的事。JS开发已经并不单纯局限在敲JS代码, 从代码的编写,到集成单元测试,再到发布,每个环节都已经专业化,很多新鲜的开发工具都需要去了解。
 
比如和CSS相关的SCSS,将编码引入到CSS中(作者肯定是一个超级懒惰的程序员),使得CSS的开发和维护效率以几何级增长;又比如时下火热的Node.js,把JavaScript移植到服务器端,可以编写Web应用、游戏服务器等等。实际Node.js并不限于服务器端开发,还可以用来编写本地脚本,实现自动化部署脚本。看看现在开源的JavaScript库,基本上都引入了基于Node.js的Grunt来实现脚本的自动化发布。
 
像我这样,接触Javascript已经很多年了,但去看Angular源码时,还是有种无处下手的尴尬。下载Angular的源码,一进去就荤菜了,一大堆的文件。经过一番探索后,总算有了点头绪。Angular是一个颇庞大的框架,发布版本(单个js文件)有1万五前多行代码(包含注释),维护这样一个文件显然不是人力所能及也,所以和很多JS库一样,在开发时将文件按照功能拆分为多个子文件,这样便于维护。发布时,使用Grunt脚本来组合以及压缩。
 
package.json和Gruntfile.js是Grunt的两个配置文件,定义了各种发布任务。AngularJS使用了bower来管理依赖的JS库,在bower.json中定义了相关信息,依赖的库有jQuery, bootstrap, closure等,不过这些库都只是在跑单元测试时才用到。有一堆以karma前缀开头的文件,这是单元测试工具karma相关的东东。如果只是看源码,可以不用理会这些非js文件,直接看src目录即可。
 
在src目录下,有三个文件:Angular.js, angular.prefix, angular.suffix。从文件名可以看出,这是程序主体。prefix是文件头部,suffix是文件尾。suffix的代码如下:
  //try to bind to jquery now so that one can write angular.element().read()
//but we will rebind on bootstrap again.
bindJQuery(); publishExternalAPI(angular); jqLite(document).ready(function() {
angularInit(document, bootstrap);
}); })(window, document);

红色部分标出的正是AngularJS的入口。AngularJS内置了jQuery的轻量版本jqLite,具体代码见src/jqLite.js。bindJquery函数会尝试去绑定jQuery库,如果没有找到,就用内置的jqLite。DOM加载完毕后,执行angularInit函数,作准备工作。

function angularInit(element, bootstrap) {
var elements = [element],
appElement,
module,
names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/; function append(element) {
element && elements.push(element);
} forEach(names, function(name) {
names[name] = true;
append(document.getElementById(name));
name = name.replace(':', '\\:');
if (element.querySelectorAll) {
forEach(element.querySelectorAll('.' + name), append);
forEach(element.querySelectorAll('.' + name + '\\:'), append);
forEach(element.querySelectorAll('[' + name + ']'), append);
}
}); forEach(elements, function(element) {
if (!appElement) {
var className = ' ' + element.className + ' ';
var match = NG_APP_CLASS_REGEXP.exec(className);
if (match) {
appElement = element;
module = (match[2] || '').replace(/\s+/g, ',');
} else {
forEach(element.attributes, function(attr) {
if (!appElement && names[attr.name]) {
appElement = element;
module = attr.value;
}
});
}
}
});
if (appElement) {
bootstrap(appElement, module ? [module] : []);
}
}

angularInit函数主要用来寻找主程序入口。如果在DOM中找到了ng-app标记,则调用bootstrap开始初始化框架。如果没有定义app标记,则需要手动调用angular.bootstrap来初始化。app标记一般在html节点,也可以放置在任意的节点上,app节点所在的DOM树都会被AngularJS框架遍历解析。

ng-app属性如果有值,即自定义module,也会被解析出来,前提是我们必须先创建module,用来管理全局的injector行为和对象。如果没有值,则会创建默认的module。

function bootstrap(element, modules) {
var doBootstrap = function() {
element = jqLite(element); if (element.injector()) {
var tag = (element[0] === document) ? 'document' : startingTag(element);
throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
} modules = modules || [];
modules.unshift(['$provide', function($provide) {
$provide.value('$rootElement', element);
}]);
modules.unshift('ng');
var injector = createInjector(modules);
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
function(scope, element, compile, injector, animate) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
});
animate.enabled(true);
}]
);
return injector;
}; var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
return doBootstrap();
} window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
angular.resumeBootstrap = function(extraModules) {
forEach(extraModules, function(module) {
modules.push(module);
});
doBootstrap();
};
}

按照官方文档描述,bootstrap步骤分为三步:首先加载module,然后创建全局injector对象,最后执行compile动作,对应的正是上面的代码。

AngularJS会为每个应用程序创建唯一的injector对象,它可以看作是一个对象池,依靠键值来存取实例,比如存放数据的model,和后端交互的service等,而实例的创建则由module来决定。

在AngularJS框架中,应用程序被看作是由多个module组成的一个结合体,而一个module,往往是相似功能块的组合。在一个大型应用程序中,我们习惯将程序切分为多个模块并行开发,这也是AngularJS的推荐做法。在module中,可以定义和View层打交道的Controller,和后台交互的Service,也可以自定义依赖注入行为,解析特殊的DOM数据。

从上面的代码可以看到,初始化时会加载内置的模块,比如“ng”。在ng模块中定义了AngularJS的核心功能,包括解析DOM树中的以“ng”为前缀的自定义节点, 比如ng-model,ng-class,ng-repeat等等。

compile,编译,顾名思义,就是将DOM中的ng标记和其他自定义标记解析为真正的View, Model和Controller等。

--------------------

到这里为止,对AngularJS的运行机制还处于一知半解,不得不吐槽下,想要弄懂AngularJS的运行机制实在不是件容易的事。

最后再补充一点:有一款名为"Batarang"的Chrome扩展插件一定不能错过,AngularJS开发调试必备。用过后,才知道官网上一些截图是怎么来的了~

AngularJS框架研究(一)的更多相关文章

  1. 简洁AngularJS框架后台管理系统bootstrap后台模板

    最近在做一个后台管理的项目,但是没有设计图完全,所以就发现一款非常不错的模版. 这个模版是基于 AngularJS 和 bootstrap 的后台管理系统模版. Minovate是 AngularJS ...

  2. 十佳AngularJS框架

    您是否还在烦恼如何没有困难地创建一个创新型的Web应用程序?那么一定不要错过这个集合!在本文中,小编为大家收集了十个非常棒的AngularJS框架.AngularJS框架拥有大量有用的工具和组件,可以 ...

  3. 10 个非常有用的 AngularJS 框架

    AngularJS是最流行的开源web app框架.AngularJS被用于解决阻碍单页应用程序开发的各种挑战. 你作为一个AngularJS用户,却不知道一些可以帮助你美化编码的资源?那么一定不能错 ...

  4. AngularJS框架速写

    最近在把玩AngularJS框架,之前也看过流行的Backbone,不过AngularJS给人的感觉完全不同,它走的是一条高帅富之路. 按照官方的说法,AngularJS是一套依赖注入的MVC开发套件 ...

  5. ASP.NET Web API 框架研究 ASP.NET Web API 路由

    ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...

  6. 关于js单页面实现跳转原理以及利用angularjs框架路由实现单页面跳转

    还记得我们刚开始学习html时使用的锚节点实现跳转吗? <a href="#target">我想跳转至目标位置</a> <p>第一条</p ...

  7. spserver 开源服务器框架研究与分析

    网上开源的C/C++服务器框架 还是比较少的. 最近研究了 spserver , 里面用了较多的设计模式,使用设计模式的目的是把不变的东西和可变的东西分离并且封装起来,避免以后修改代码, 应用设计模式 ...

  8. 基于Jmeter和Testlink的自动化测试框架研究与实施

    关于测试框架搭建的详细过程,会在另一篇文章中详细介绍:http://www.cnblogs.com/leeboke/p/6145977.html 摘 要 目前基于Jmeter的接口自动化测试框架,大多 ...

  9. angularjs框架及其生态环境 --待续

    angular的MVVM框架结构:     1. app,   2.routes, config,   3.module,   4.Controller, $scope,controller参数,事件 ...

随机推荐

  1. Swift学习笔记(一)搭配环境以及代码运行成功

    原文:Swift学习笔记(一)搭配环境以及代码运行成功 1.Swift是啥? 百度去!度娘告诉你它是苹果最新推出的编程语言,比c,c++,objc要高效简单.能够开发ios,mac相关的app哦!是苹 ...

  2. 饼干怪兽和APT攻击

    APT攻击就像一个孩子,你通过各种方式窃取他们的大脑要拿出饼干,为了防止恶意攻击,过失作为母亲未能发现和防止饼干盗窃贼如.于她仅仅监视厨房椅子.衣柜门或烤箱门的开启.建立起有效防御目标攻击与APT攻击 ...

  3. Java-继承特性

    继承的特点: 1.提高了代码的复用性. 2.让类与类之间发生了关系,有了这个关系,才有了多态的特性. (注意:千万不要为了获取其他类的功能,简化代码而继承:必须是类与类之间有所属关系才可以继承,所属关 ...

  4. PHP版本的区别

    原文:PHP版本的区别 以为这个已经写过了,发现没有,赶紧补充下. PHP的版本,自从进入5以后,发布新版本速度明显提升很多,从PHP5.2开始,5.3 .5.4 .5.5,就快要6.0了. 注:ec ...

  5. 微软不也是从Altair Basic这丑小鸭长成白天鹅吗?

    微软不也是从Altair Basic这丑小鸭长成白天鹅吗? February 2015 如果你想要弄清楚初创企业是怎么一回事的话,其中一个非常有价值的尝试是去研究下那些获得巨大成功的公司,去分析下为什 ...

  6. 基于科大讯飞语音云windows平台开发

    前记: 前段时间公司没事干,突发奇想想做一个语音识别系统,看起来应该非常easy的,但做起来却是各种问题,这个对电气毕业的我,却是挺为难的.谷姐已经离我们而去,感谢度娘,感谢CSDN各位大神,好歹也做 ...

  7. CSS学习笔记之CSS的继承、层叠和特殊性

    继承 CSS的某些样式是具有继承性的,那么什么是继承呢?继承是一种规则,它允许样式不仅应用于某个特定html标签元素,而且应用于其后代.比如下面代码:如某种颜色应用于p标签,这个颜色设置不仅应用p标签 ...

  8. leetcode第三题--Longest Substring Without Repeating Characters

    Problem:Given a string, find the length of the longest substring without repeating characters. For e ...

  9. js获取非行间样式或定义样式

    <!--DOCTYPE html--> <html> <head> <meta charset="utf-8" /> <sty ...

  10. js 拖拽实现

    代码参考 <!DOCTYPE html> <html lang="en"> <title>拖拽</title> <head&g ...