1
0

More than 5 years have passed since last update.

Angular - 概念综述

Last updated at Posted at 2013-02-24

启动期

以下描述解释了一个简单的 Hello World! 应用的启动过程:

  1. 浏览器加载 HTML 并解析成 DOM

  2. 浏览器加载 angular.js 脚本

  3. Angular 等待 DOMContentLoaded 事件

  4. Angular 寻找 ng-app(指令),这个指令界定了应用程序的作用范围(边界)

  5. ng-app 中指定的 Module(如果有的话)被用来配置 $injector(注入器)

  6. $injector 用于创建 $compile(编译器) 服务以及 $rootScope(根作用域)

  7. $compile 服务用于编译 DOM 并将其连接至 $rootScope

  8. ng-init(指令) 将 "World" 这个字符串赋值给当前作用域下的 name 属性

  9. {{ name }}(插入型表达式)name 属性插入 DOM,生成 "Hello World!"

启动过程

源代码

<!DOCTYPE html>
<html ng-app>
    <head>
        <script scr="angular.js"></script>
    </head>
    <body>
        <!-- 这里只是范例,实际上通常都是在 controller 里进行赋值而不是在这里 -->
        <p ng-init="name='World'">Hello {{ name }}!</p>
    </body>
</html>

运行期

以下内容描述了 Angular 如何与浏览器的事件回圈进行交互:

  1. 浏览器的 event-loop(事件回圈) 等待一个事件的到达;一个事件可能是一次用户交互,也可能是一个计时器,或者是网络事件(比如来自服务器的响应)

  2. 事件的回调函数执行,这将进入 JavaScript 的语境(也就是 context,或称“上下文环境”)。回调函数可以修改 DOM 的结构

  3. 一旦回调函数执行完毕,浏览器离开 JavaScript 语境,并根据 DOM 的变化重新渲染视图

运行期

上图右边显示出 Angular 通过提供自己的事件处理回圈机制来改变 JavaScript 的执行流程,这种机制将 JavaScript 语境分成两部分:传统的执行语境和 Angular 的执行语境。只有应用于 Angular 执行语境的操作才能受益于 Angular 的数据绑定(data-binding),异常处理(Exception handling),属性监视(property watching),等等……也可以通过使用 $apply() 来进入 Angular 的执行语境。

要注意的是在绝大多数地方(控制器,服务),$apply() 已经通过指令(指令用来处理事件)被调用了(简言之,在 Angular 的执行语境下,没有必要显式调用它)。只有在需要执行自定义的事件回调函数,或是在处理第三方库的回调之时才需要显式调用 $apply()

  1. 通过调用 scope.$apply (stimulusFn) 进入 Angular 的执行语境。stimulusFn 既是你想要在 Angular 执行语境下做的一切事情。

  2. Angular 执行 stimulusFn(),通常这会改变应用程序的状态

  3. Angular 进入 $digest loop,这个回圈本身由两个更小的回圈组成,一个用来处理 $evalAsync queue,另一个用来处理 $watch list$digest loop 不断地迭代直到模型稳固下来,技术层面上讲就是 $evalAsync queue 为空并且 $watch list 没有侦测到任何变化的时刻

  4. $evalAsync queue 用来安排一些特定的(需要异步执行的)工作,这里特指那些需要出现在当前堆栈帧(current stack frame)以外(执行位置),并在浏览器视图渲染之前(执行时间)的工作。这种机制常常(非 Angular)是用 setTimeout(0) 来实现的,但是 setTimeout(0) 要么会变得缓慢,要么会引起视图闪烁(因为浏览器在每一个事件结束之后渲染视图)

  5. $watch list 保存了一组自上次迭代后可能发生了改变的表达式。在侦测到某个变动之时 $watch 函数即被调用,并且通常会用新值来更新 DOM

  6. 一旦 $digest loop 完成,并离开 Angular 和 JavaScript 的执行语境之后,浏览器就紧跟着去重绘 DOM 以响应任何变化

以下是另一个解释,描述了如何实现数据绑定效果(用户在文本框输入文字):

  1. 在编译期阶段:

    1. ng-modelinput 指令为 <input> 设置了一个 keydown 事件监听器
    2. {{ name }} 插值表达式产生了一个 $watch 用以响应 name 的变化
  2. 在运行期阶段:

    1. 按下 'x' 键会使浏览器触发设置在 <input> 上的 keydown 事件
    2. input 指令捕捉了这一变化然后调用了 $apply("name='x';") 来更新应用程序模型(在 Angular 执行语境内)
    3. Angular 将 name = 'x'; 应用给模型
    4. $digest loop 开始
    5. $watch list 侦测到了 name 属性的变化并且通知 {{ name }} 插值表达式(令其重新解析),最终这将转变成 DOM 的更新
    6. Angular 退出自身执行语境,继而退出 keydown 事件和相关的 JavaScript 执行语境

源代码

<!DOCTYPE html>
<html ng-app>
    <head>
        <script src="angualr.js"></script>
    </head>
    <body>
        <input ng-model="name">
        <p>Hello {{ name }}!</p>
    </body>
</html>

作用域

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0