什么是变化检测?

变化检测的基本功能就是获取应用程序的内部状态(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. 设计模式C++学习笔记之九(Template Method模板方法模式)

      模板模式也是相当简单的一种模式,而且是比较常用的.模板模式是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些 ...

  2. python3之模块SMTP协议客户端与email邮件MIME对象

    转载自https://www.cnblogs.com/zhangxinqi/p/9113859.html 阅读目录 1.smtplib模块的常用类与方法 2.处理邮件MIME 3.实例 (1)使用HT ...

  3. 求逆序对 ----归并排 & 树状数组

    网上看了一些归并排求逆序对的文章,又看了一些树状数组的,觉得自己也写一篇试试看吧,然后本文大体也就讲个思路(没有例题),但是还是会有个程序框架的 好了下面是正文 归并排求逆序对 树状数组求逆序对 一. ...

  4. Python Redis pipeline操作

    Redis是建立在TCP协议基础上的CS架构,客户端client对redis server采取请求响应的方式交互. 一般来说客户端从提交请求到得到服务器相应,需要传送两个tcp报文. 设想这样的一个场 ...

  5. 【原创】大数据基础之Benchmark(4)TPC-DS测试结果(hive/hive on spark/spark sql/impala/presto)

    1 测试集群 内存:256GCPU:32Core (Intel(R) Xeon(R) CPU E5-2640 v3 @ 2.60GHz)Disk(系统盘):300GDisk(数据盘):1.5T*1 2 ...

  6. Android存储路径你了解多少?

    在了解存储路径之前,先来看看Android QQ的文件管理界面,了解一下QQ的数据文件路径来源,到底是来源于什么地方? 手Q文件管理对应存储目录 我的文件:是指放在QQ指定目录下的文件:/tencen ...

  7. linux学习之软件包安装

    本学习基于redhat系统或者centos系统 一.软件包的安装 1.rpm安装,rpm安装分为俩种,一种是直接安装xxx.rpm包,另一种是通过yum安装一系列的rpm包. #推荐使用yum安装,y ...

  8. (转)scikit-learn主要模块和基本使用方法

    从网上看到一篇总结的很不错的sklearn使用文档,备份勿忘. 引言 对于一些开始搞机器学习算法有害怕下手的小朋友,该如何快速入门,这让人挺挣扎的.在从事数据科学的人中,最常用的工具就是R和Pytho ...

  9. spring各版本jar包和源码

    spring各版本jar包和源码 spring历史版本源码:https://github.com/spring-projects/spring-framework/tags spring历史jar包和 ...

  10. window Maven私服搭建——nexus

    注:本文来源于 <window   Maven私服搭建--nexus> Maven私服搭建--nexus 1.下载nexus https://www.sonatype.com/downlo ...