Angular学习笔记(16)—揭秘Angular

当浏览器触发DOMContentLoaded事件时,Angular就开始工作。它首先寻找ng-app指令。如果浏览器在DOM中找到ng-app指令,它会为我们自动启动应用。如果没有找到这个指令,Angular期望我们自己手动启动应用。
要手动启动一个AngularJS应用,可以使用Angular的bootstrap()方法。在一些罕见的情况下手动启用应用程序是有意义的。例如,想要在某个其他库的代码运行之后,或者在运行时动态创建元素时,启动AngularJS应用。要想手动启动应用,可以像下面这样启动它:

var newElement = document.createElement("div");
angular.bootstrap(newElement, ['myApp']);

如果在DOM中没有找到ng-app指令,而且也没有手动启动应用,则AngularJS不会运行。忘记在页面中引入ng-app指令肯定会引发一些严重的问题。
bootstrap()方法只允许我们启动angular应用一次。
如果在ng-app属性中没有指定应用程序,则Angular会加载一个不带特定模块的应用。如果指定了,Angular就会加载与这个指令关联的模块。
一旦应用程序加载完成,$injector就会在应用程序的$rootScope旁边创建$compile服务。
$rootScope创建后,$compile服务就会接管它。它会将$rootScope与现有的DOM连接起来,然后从将ng-app指令设置为祖先的地方开始编译DOM。

视图的工作原理

当浏览器在标准的Web流程中获取HTML时,它会收到HTML代码并将它解析为一个DOM树。这个DOM树中的每个元素被称作DOM元素,这些DOM元素会构建一堆节点。然后浏览器负责绘制出这个DOM树的结构。
浏览器在提取脚本时(从<script>标签中),会暂停DOM解析并等待脚本取回(你可以修改这一行为,但是这个行为是默认的)。
angular.js被取回时,浏览器会执行它,同时设置一个事件监听器来监听浏览器的DOMContentLoaded事件。DOMContentLoaded事件会在HTML文档加载完成并开始解析时触发。
检测到这个事件时,Angular会查找ng-app指令,然后创建运行需要的一系列必要的组件(即$injector$compile服务以及$rootScope),然后开始解析DOM树。

编译阶段

$compile服务会遍历DOM树并搜集它找到的所有指令,然后将所有这些指令的链接函数合并为一个单一的链接函数。
然后这个链接函数会将编译好的模板链接到$rootScope中(也就是附属于ng-app所在的DOM元素的作用域)。
它会通过检查DOM属性、注释、类以及DOM元素名称的方式查找指令。
$compile服务通过遍历DOM树的方式查找有声明指令的DOM元素。当碰到带有一个或多个指令的DOM元素时,它会排序这些指令(基于指令的priority优先级),然后使用$injector服务查找和收集指令的compile函数并执行它。
指令中的compile函数会在适当的时候处理所有DOM转换或者内联模板,如同创建模板的副本。

// 返回一个链接函数
var linkFunction = $compile(appElement);
// 调用链接函数,将$rootScope附加给DOM元素
linkFunction($rootScope);

每个节点的编译方法运行之后,$compile服务就会调用链接函数。这个链接函数为绑定了封闭作用域的指令设置监控。这一行为会创建实时视图。
最后,在$compile服务完成后,AngularJS运行时就准备好了。

运行时

在标准的浏览器流程中,事件循环会等待事件执行(比如鼠标移动、点击、按键等)。当这些事件发生时,它们会被放到浏览器的事件队列中。如果有函数处理程序对事件作出响应,浏览器就会将event对象作为参数来调用这些事件处理程序。

ele.addEventListener('click', function(event) {});

Angular中对事件循环做了一点增强,并且Angular还提供了自己的事件循环。指令自身会注册事件监听器,因此当事件被触发时,指令函数就会运行在AngularJS的$digest循环中。
Angular的事件循环被称作$digest循环。这个$digest循环由两个小型的循环组成,分别是evalAsync循环和$watch列表。
当事件被触发时,事件处理程序就会在指令的上下文中进行调用,也就是AngularJS的上下文中。从功能上讲,AngularJS会在包含作用域的$apply()方法内调用指令。Angular是在$rootScope上启动$digest循环时开始整个过程的,并且还会传播到所有子作用域中。
Angular进入$digest循环时,会等待$evalAsync队列清空,然后再将回调执行上下文交还给浏览器。这个$evalAsync用于在浏览器进行渲染之前,调度需要运行在当前桢栈之外的所有任务。
此外,$digest循环还会等待$watch表达式列表,它是一个可能在上一次迭代过程中被改变的潜在的表达式数组。如果检测到变化,就调用$watch函数,然后再次查看$watch列表以确保没有东西被改变。
注意,对于$watch列表中检测到的任何变化,AngularJS都会再次查看这个列表以确保没有东西被改变。
一旦$digest循环稳定下来,并且检测到没有潜在的变化了,执行过程就会离开Angular上下文并且通常会回到浏览器中,DOM将会被渲染到这里。
整个流程在每个浏览器事件之间都会发生,这也是Angular如此强大的原因。它还可以将来自浏览器的事件注入到AngularJS流程中。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351

推荐阅读更多精彩内容