什么是变化检测?

变化检测的基本功能就是获取应用程序的内部状态(state),并且是将这种状态对用户界面保持可见.状态可以是javascript中的任何的数据结构,比如对象,数组,(数字,布尔,字符串等基础数据类型).这种状态最终可能成为用户界面中的段落,表单,链接或按钮,在web浏览器中我们们称之为文档对象模型(dom).将数据结构作为输入生成dom作为输出并展示给用户,我们称这个过程为渲染.

但是,在运行时发生更改时会变得更加棘手。一段时间后,DOM已经被渲染。我们如何弄清楚模型中发生了哪些变化,以及我们需要在哪里更新DOM?访问DOM树总是很昂贵,因此我们不仅需要找出需要更新的位置,而且还希望尽可能小地保持访问权限.这可以通过许多不同的方式解决。例如,一种方法是简单地发出http请求并重新呈现整个页面。另一种方法是将新状态的DOM与先前状态进行区分并仅渲染差异的概念,这就是React使用Virtual DOM进行的操作.

因此,变更检测的目标始终是预测数据及其变化。

什么导致变化发生?

现在我们知道变化检测的全部内容,我们可能想知道,何时会发生这样的变化? Angular什么时候知道它必须更新视图?好吧,我们来看看下面的代码

@Component({
template: `
<h1>{{firstname}} {{lastname}}</h1>
<button (click)="changeName()">Change name</button>
`
})
class MyApp { firstname:string = 'Pascal';
lastname:string = 'Precht'; changeName() {
this.firstname = 'Brad';
this.lastname = 'Green';
}
}

上面的组件只显示两个属性,并提供了一种方法,可以在单击模板中的按钮时更改它们。单击此特定按钮的那一刻是应用程序状态发生更改的时刻,因为它会更改组件的属性。那是我们想要更新视图的那一刻。

又比如:

@Component()
class ContactsApp implements OnInit{ contacts:Contact[] = []; constructor(private http: Http) {} ngOnInit() {
this.http.get('/contacts')
.map(res => res.json())
.subscribe(contacts => this.contacts = contacts);
}
}

该组件包含联系人列表,在初始化时,它会执行http请求。一旦此请求返回,列表就会更新。同样,此时,我们的应用程序状态已更改,因此我们将要更新视图。

应用程序状态改变一般由以下3个方面引起:

  1. 事件: click,input,submit...
  2. XHR: 从远程服务器获取数据
  3. 定时器:setTimeout(),setInterval()

事实证明,这三件事有一些共同之处。你能说出来吗? ......正确!它们都是异步的.

为什么你认为这很重要?嗯......因为事实证明,当Angular真正对更新视图感兴趣时,这些是唯一的情况。假设我们有一个Angular组件,当单击一个按钮时它会执行一个处理程序:

@Component({
selector: 'my-component',
template: `
<h3>We love {{name}}</h3>
<button (click)="changeName()">Change name</button>
`
})
class MyComponent { name:string = 'thoughtram'; changeName() {
this.name = 'Angular';
}
}

单击组件的按钮时,将执行changeName(),这将更改组件的name属性,由于我们希望此更改也反映在DOM中,因此Angular将相应地更新视图绑定{{name}}。很好,这似乎神奇地工作.

另一个例子是使用setTimeout()更新name属性。请注意,我们删除了该按钮。我们不是必须去做一些特殊的事情来通知框架状态 发生了变化

@Component({
selector: 'my-component',
template: `
<h3>We love {{name}}</h3>
`
})
class MyComponent implements OnInit { name:string = 'thoughtram'; ngOnInit() {
setTimeout(() => {
this.name = 'Angular';
}, 1000);
}
}

谁通知Angular进行变化检测?

  Angular允许我们直接使用本机API。我们不需要调用拦截器方法,因此Angular会通知更新DOM。这是纯粹的魔法吗? 背后的秘密就是Angular利用了Zones库.Zones猴子补丁全局异步操作,如setTimeout()和addEventListener(),这就是Angular可以轻松找到的原因,何时更新DOM. 简短的版本是,在Angular的源代码中,有一个名为ApplicationRef的东西,它监听NgZones onTurnDone事件。每当触发此事件时,它都会执行tick()函数,该函数基本上执行更改检测。

// very simplified version of actual source
class ApplicationRef { changeDetectorRefs:ChangeDetectorRef[] = []; constructor(private zone: NgZone) {
this.zone.onTurnDone
.subscribe(() => this.zone.run(() => this.tick());
} tick() {
this.changeDetectorRefs
.forEach((ref) => ref.detectChanges());
}
}

变化检测执行机制

一个重要的事实是:我们可以为每个组件单独控制如何以及何时执行更改检测

  由于每个组件都有自己的更改检测器,而Angular应用程序由组件树组成,因此逻辑结果是我们也有一个更改检测器树。此树也可以视为有向图,其中数据始终从顶部流向底部.数据从上到下流动的原因是因为每个单独的组件,从根组件开始,每个组件也始终从上到下执行更改检测。这很棒,因为单向数据流比循环更容易预测。相比之下,AngularJS采用的是双向数据流,错综复杂的数据流使得它不得不多次检查,使得数据最终趋向稳定。理论上,数据可能永远不稳定。AngularJS给出的策略是,脏检查超过10次,就认为程序有问题,不再进行检查。我们总是知道我们在视图中使用的数据来自何处,因为它只能来自其组件。在Angular 2+中,另一个有趣的观察是一次通过后变化检测变得稳定。这意味着,如果我们的某个组件在更改检测期间第一次运行后导致任何其他副作用,Angular将抛出错误。在开发模式下,Angular会进行二次检查,如果出现上述情况,二次检查就会报错:Expression Changed After It Has Been Checked Error。而在生产环境中,脏检查只会执行一次。

    

变化检测性能

  默认情况下,即使我们每次都要检查事件发生时每个组件,Angular都非常快。它可以在几毫秒内执行数十万次检查。这主要是因为Angular生成了VM友好代码。那是什么意思?好吧,当我们说每个组件都有自己的变化检测器时,它不像Angular中的这个通用的东西,它负责每个组件的变化检测。原因是它必须以动态方式编写,因此无论模型结构如何,它都可以检查每个组件。虚拟机不喜欢这种动态代码,因为它们无法对其进行优化。它被认为是多态的,因为物体的形状并不总是相同的。

  Angular在运行时为每个组件创建变化检测器类,这些组件是单态的,因为它们确切地知道组件模型的形状。 VM可以完美地优化此代码,从而使其执行起来非常快。好消息是我们不必过多关心它,因为Angular会自动完成它。    

  本篇简单介绍下angular 2+变化检测的基础,下一篇重点讲一下变化检测策略.

       

angular 2+ 变化检测系列一(基础概念)的更多相关文章

  1. .NET技术面试题系列(1) 基础概念

    这是.NET技术面试题系列第一篇,今天主要分享基础概念. 1.简述 private. protected. public.internal 修饰符的访问权限 private : 私有成员, 在类的内部 ...

  2. 快速入门系列--WCF--01基础概念

    转眼微软的WCF已走过十个年头,它是微软通信框架的集大成者,将之前微软所有的通信框架进行了整合,提供了统一的应用方式.记得从自己最开始做MFC时,就使用过Named Pipe命名管道,之后做Winfo ...

  3. angular 2+ 变化检测系列三(Zone.js在Angular中的应用)

    在系列一中,我们提到Zone.js,Zones是一种执行上下文,它允许我们设置钩子函数在我们的异步任务的开始位置和结束位置,Angular正是利用了这一特性从而实现了变更检测. Zones.js非常适 ...

  4. 快速入门系列--TSQL-01基础概念

    作为一名程序员,对于SQL的使用算是基础中的基础,虽然也写了很多年的SQL,但常常还是记不清一些常见的命令,故而通过一篇博文巩固相关的记忆,并把T-SQL本身的一些新特性再进行一次学习. 首先回顾基础 ...

  5. angular 2+ 变化检测系列二(检测策略)

    我们将创建一个简单的MovieApp来显示有关一部电影的信息.这个应用程序将只包含两个组件:显示有关电影的信息的MovieComponent和包含执行某些操作按钮的电影引用的AppComponent. ...

  6. zabbix学习系列之基础概念

    触发器 概念 "监控项"仅负责收集数据,而通常收集数据的目的还包括在某指标对应的数据超出合理范围时给相关人员发送警告信息,"触发器"正式英语为监控项所收集的数据 ...

  7. QUARTZ系列之一-基础概念(Scheduler/Job/JobDetail/Trigger)

    摘抄自quartz官方文档: The key interfaces of the Quartz API are: Scheduler - the main API for interacting wi ...

  8. 理解 angular2 基础概念和结构 ----angular2系列(二)

    前言: angular2官方将框架按以下结构划分: Module Component Template Metadata Data Binding Directive Service Dependen ...

  9. MongoDB入门系列(一):基础概念和安装

    概述 MongoDB是目前非常流行的一种非关系型数据库,作为入门系列的第一篇本篇文章主要介绍Mongdb的基础概念知识包括命名规则.数据类型.功能以及安装等. 环境: OS:Windows Versi ...

随机推荐

  1. eclipse 迁移项目 乱码

    eclipse 迁移项目总是乱码问题,网上解决都无非是把workspace.项目.文件等改成utf-8,但总是不好使,因为原来有的文件类型还是要改成原来的编码格式,可以使用文本工具如notepad打开 ...

  2. Docker部署tomcat及应用

    前提Docker已安装完成. 由于测试网无法直接连入互联网,所以在本机虚拟机内下载tomcat镜像并传到测试网主机中. 虚拟机内执行 查找tomcat镜像: # docker search tomca ...

  3. 开源录屏工具 Best Screen Recording Open Source Software For Windows 2017

    OBS Studio OBS (Open Broadcaster Software) - Free and open source software for live streaming and sc ...

  4. MR1和MR2(Yarn)工作原理流程

    一.Mapreduce1 图1  MR1工作原理图 工作流程主要分为以下6个步骤: 1 作业的提交 1)客户端向jobtracker请求一个新的作业ID(通过JobTracker的getNewJobI ...

  5. 请在微信客户端打开链接 html

    1 前言 有时候,需要链接只能在微信上打开,如果不是,则提示请在微信客户端打开链接的字眼的网页,网页代码如下:(这个是网页应用授权时,非微信上打开,就会出现,然后把它单独拿出来了) 2 代码 < ...

  6. Python-Pool类

    目录: multiprocessing模块 Pool类 apply apply_async map close terminate join 进程实例 multiprocessing模块 如果你打算编 ...

  7. LuoGu P1004 方格取数

    题目传送门 一开始这个题我是不会的(沙华弱DP啊QwQ),后来考完试我一想,这东西怎么和数字三角形那题这么像啊? 都是自上而下,只能向下或者向右,求一个max 那么...这不就是个走两遍的数字矩阵嘛 ...

  8. FileStorage

    1. 函数说明                  功能 函数声明 参数 FileStorage构造函数 cv::FileStorage:: FileStorage(const String& ...

  9. Confluence 6 开始使用

    欢迎来到 Confluence 的开始使用指南文档.在这个稳定中,你将会找到有关对 Confluence 进行评估的指南和其他的一些有用的内容.当你开始使用 Confluence 的时候,这些信息能够 ...

  10. Confluence 6 从外部目录中同步数据配置同步间隔

    在用户目录(User Directories)界面中显示了最后的系统同步时间,包括有这次同步所花费的时间. 注意:针对 Crowd  和 Jira 目录同步时间的配置只在 Confluence 3.5 ...