文档章节

AngularJS原理篇

余诺
 余诺
发布于 2014/07/23 16:34
字数 1735
阅读 1110
收藏 5

为了更好的解耦,各个框架(Extjsjquery)的目标都是实现MVC,只是方式不同,而angular采用的是双向数据绑定。

图片摘自《用AngularJS开发下一代WEB应用》中文译者大漠穷秋的博客

如图,为了要实现双向数据绑定,angular以指令、scope、依赖注入、digest作为基础,而这些最终都是依赖于底层的JS版编译器。MVCServicefactorymodule上次都已经有介绍,那么这次我们先从compiler开始讲起。

一、compilerdirectives

相关源码可见src/ng/compiler.js(本篇源码的版本号1.3.0-beta.11,下同)。

angular实现了一个JS版的编译器,如我们所知的编译器一样,会有编译(compiler)、链接(link)两个过程。

compiler过程主要包含:

1. 将所有指令按优先级排序(详见collectDirectives函数);

2. 执行每个指令的compile函数(详见applyDirectivesToNode函数),如果一个指令需要被克隆很多次(比如:ng-repeat),compile函数只在编译阶段被执行一次,复制这些模板,但是link函数会针对每个被复制的实例来执行;

3. 把每个compile函数返回的link函数打包到一个总的link函数中(详见compileNodes函数)

link过程主要包含:

1. scope绑定到DOM上;(详见nodeLinkFn函数)

2. 在元素上注册事件监听器;

3. 使用$watch监控数据模型,从而获知值的变化;

常见的一些JS Template框架也采用了类似的compile策略以提升效率,比如HandleBarsExtJSXTemplate。从这个角度来看,可以把angular的指令看作增强版的JS Template机制。

 

二、依赖注入(DI)

相关源码可见src/auto/injector.js

熟悉Java的对依赖注入应该都不会陌生,Java实现依赖注入主要有三种方式:接口注入、set注入、构造注入,而angular采用的是构造注入。

 

代码分析:

98-使用toString()来获得方法的定义

99-正则表达式来查找方法的标志

100-102-解析注入参数成array,并保存到$inject

115-返回参数集合

之所以有fnarray的区别是因为依赖注入有以下两种写法:

 

angular在获取到注入参数后,根据参数名称来获取对象实体,从而注入所需对象:

 

既然是根据参数名称,对于fn的解析方式在进行js代码压缩时,如果把$scope$http压缩改名,则angular将找不到其对应的对象,会导致应用程序出错,而array的方式将能保留参数的字符串名称。

所以在定义你的服务时请尽量使用array的方式来定义参数。

 

三、双向数据绑定

相关源码可见src/ng/rootScope.js

双向数据绑定的核心问题是“脏值检测”——如何去判断值变化,难点是“循环依赖问题”——当值一直在变化(比如两个相互依赖的值发生改变),无法达到稳定状态(即值不变)时如何处理。

前面link过程中有说angular使用$watch来监控数据模型,以此来判断值的变化情况。我们先来看看$watch函数:

 

参数:

watchExp:需要监视的值或表达式

listener:监听函数,值变化时执行

objectEquality:是否开启值检测,为true时会检测对象或者数组内部变更(即选择以===的方式比较还是angular.equals的方式)

内部变量:

arrayscope.$$watchers:存储注册过的所有监听器。每次digest时会去遍历array中所有监听器观察值的变化,直到值停止变更时才停止。

watcher

last:监视对象的旧值,用于与现在的值进行比较来确定值是否改变。如果不相同,监听器就是dirty=true,它的监听函数就应当被调用。

返回值:

返回值是个函数,如果执行该函数,就会把刚注册的这个监听器销毁。

 

当监听到任何变化时,都会触发$digest循环:

 

$digest函数中会遍历所有监听器,并比对所有监听的值的变化。如果所有监听器的值都没变化,则dirty=false,不需要做任何更新;如果有任何监听器的值发生改变,则设置dirty=true,并修改对应值,$digest也会再次执行,直到所有的监听器值没有了改变。

注:JavaScript里,NaNNot-a-Number)并不等于自身所以在脏检测函数里不显式处理NaN因为一个值为NaN的监听器会一直是dirty

 

那如何解决循环依赖呢?angular采用控制检测值变化的迭代次数:TTL,默认为10次。

如果超出迭代次数,值还不稳定,则抛出异常。

一般情况下开发者是不需要直接用$digestangular提供的接口是$apply

 

$apply使用函数作参数,它用$eval执行这个函数,然后通过$digest触发digest循环。而且$apply只有在创建一个不是angular库方法执行序列时才需要手动调用,因为angular的事件及异步请求等都会自动调用$apply

注:在使用$apply时,请将要执行的事情包裹在$apply里面(即$scope.$apply(fn)的方式),因为如果要执行的事情出现异常,angular将无法捕获异常而导致出错,而$scope.$apply()已做了异常处理,并保证$digest()一定会被执行。

angular中还有一种延迟代码的方式,详见scope上的$evalAsync函数,它接受一个函数,把它列入计划,在当前正持续的digest中或者下一次digest之前执行。还实现了$$postDigest函数将执行计划记录在$$postDigestQueue中,digest之后运行为了不影响到被列入计划将要执行的那个digestangularscope实现了一种叫做阶段(phase)的东西。

 

通过$watch循环检测,每次viewmodel改变时,该改变都能被捕捉到,通过$digest循环修改对应的modelview,直到稳定状态,从而实现双向数据绑定。

 

结语:

除了以上介绍的这些之外,angular还有很多东西值得我们去深入探究和使用,如路由(routing)、表单校验,还有单元测试和集成测试,有兴趣的朋友可以自己去探索一番。

最后再推荐一个学习资源集合:github上搜索AngularJS-Learning

随着angular的发展,angular2.0已经在开发中。Angular2.0是一个针对移动应用的框架,同时也支持桌面环境。Angular2.0将基于ECMAScript6编写,有更快的更新检测(使用Object.observe()),更强大的功能(触摸动画、路由等),让我们一起期待。


© 著作权归作者所有

余诺
粉丝 5
博文 14
码字总数 7617
作品 0
杭州
程序员
私信 提问
[Angular Material完全攻略] Day 01 - 开始 & 简介

转载 从Angular第2版正式release后,根据全球最大工程师讨论区StackOverflow的统计,从2016开始的Angular讨论度就不断窜升,甚至超越了React,直到了2017年,甚至摆脱了前一代Angularjs的阴影...

readilen
2018/05/21
0
0
如何将你的 AngularJS 1.x 应用迁移至 React

Angular 和 React 都是伟大的框架/库。Angular 提供了 MVC(模型、视图、控制器)的定义结构。React 提供基于状态变化的轻量级呈现机制。通常情况下,开发者在 AngularJS 上有一个旧的应用程...

oschina
2018/01/29
1K
0
angular.js 1.3.17/1.4.2 发布

其中:1.3.17 更新内容如下: Bug Fixes +- **$browser:** prevent infinite digest if changing hash when there is no hashPrefix + ([61a3fb67](https://github.com/angular/angular.js/......

oschina
2015/07/07
2.6K
9
我们为什么以及是如何从 Angular.js 迁移到 Vue.js?

在我写这篇文章的时候,我们刚刚从我们的应用程序代码库中删除了最后一行AngularJS代码,结束了一个为期4个月的非侵入性工作,将我们的应用程序从AngularJS迁移到VueJS。在这篇文章中,我将分...

oschina
2017/10/19
11.1K
43
OSChina 技术专题之 AngularJS 更新版(201412)

Angular JS (Angular.JS) 是一组用来开发Web页面的框架、模板以及数据绑定和丰富UI组件。它支持整个开发进程,提供web应用的架构,无需进行手工DOM操作。 AngularJS很小,只有60K,兼容主流浏...

OSC编辑部
2014/10/17
11.1K
26

没有更多内容

加载失败,请刷新页面

加载更多

北斗三号IGSO-2卫星发射成功!

6月25日,中国航天科技集团官方公众号宣布,北斗三号IGSO-2卫星发射成功! 航天科技集团表示,6月25日2点09分,我国在西昌卫星发射中心用长征三号乙运载火箭成功将北斗三号第2颗倾斜地球同步...

linuxCool
3分钟前
0
0
阿里java开发规约的Idea插件安装(英文)

Idea Plugin Prepare Project JDK: 1.7+ Gradle: 3.0+(Require JDK1.8+ for gradle) Build cd p3c-ideagradle clean buildPlugin Run plugin cd p3c-ideagradle runIde# run speci......

Airship
12分钟前
0
0
很多人转行做程序员选择web前端学习,前端简单在哪里?

不管你是工人阶层还是服务行业,是否想过转行IT,转行IT后肯定会选择一门编程语言进行深入学习,很多转行的人基础都不是太好,不是科班出身,甚至有的是专科乃至中专,前端的HTML和CSS相对其...

智云编程
25分钟前
0
0
一文读懂内网、公网和NAT

我们做弱电监控系统的时候,都避免不了要跟IP地址打交道,比如摄像头、NVR、服务器等这些设备安装好之后,就需要给它们配上IP,那这个IP地址你了解嘛?今天我们就一起来聊聊什么是内网、公网和...

老孟的Linux私房菜
30分钟前
3
0
聊聊dubbo的ExecuteLimitFilter

序 本文主要研究一下dubbo的ExecuteLimitFilter ExecuteLimitFilter dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExecuteLimitFilter.java public clas......

go4it
39分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部