angular 2+ 变化检测系列一

什么是变化检测?

变化检测的基本功能就是获取应用程序的内部状态(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+变化检测的基础,下一篇重点讲一下变化检测策略.

       

原文地址:https://www.cnblogs.com/hanshuai/p/9362563.html

时间: 2024-11-14 12:39:48

angular 2+ 变化检测系列一的相关文章

Angular入门

Angular入门 这个系列一共会涉及两个JavaScript框架的讲解,一个是Express用做后端,一个是Angular用于前端.和Express一样,Angular分离内容,处理视图.数据和逻辑.和MVC模式很相似,但其实Angular定义是MVW框架,W代表(what ever works for you).意味着它可以是控制器或者视图模型,或者服务,就看你怎么定义的.这一节会介绍基本的Angular知识:然后改造我们之前做的页面:并且调用之前的定义的api来获取数据. Angular的

详解angular2组件中的变化检测机制(对比angular1的脏检测)

组件和变化检测器 如你所知,Angular 2 应用程序是一颗组件树,而每个组件都有自己的变化检测器,这意味着应用程序也是一颗变化检测器树.顺便说一句,你可能会想.是由谁来生成变化检测器?这是个好问题,它们是由代码生成. Angular 2 编译器为每个组件自动创建变化检测器,而且最终生成的这些代码 JavaScript VM友好代码.这也是为什么新的变化检测是快速的 (相比于 Angular 1.x 的 $digest).基本上,每个组件可以在几毫秒内执行数万次检测.因此你的应用程序可以快速执

angular 有关侦测组件变化的 ChangeDetectorRef 对象

我们知道,如果我们绑定了组件数据到视图,例如使用 <p>{{content}}</p>,如果我们在组件中改变了content的值,那么视图也会更新为对应的值. angular 会在我们的组件发生变化的时候,对我们的组件执行变化检测,如果检测到我们的数据发生了变化,就会执行某些操作,如修改绑定数据的时候更新视图. 这样一来,当我们的组件数据比较多的时候,angular就会有很多操作在静悄悄地进行,一个规避这个问题的方法是,设置某个组件的变化检测策略为 'OnPush'. 使用 OnP

用VSCode开发一个asp.net core 2.0+angular 5项目(4): Angular5全局错误处理

第一部分: http://www.cnblogs.com/cgzl/p/8478993.html 第二部分: http://www.cnblogs.com/cgzl/p/8481825.html 第三部分: https://www.cnblogs.com/cgzl/p/8525541.html 这篇文章将介绍angular 5的全局错误处理. 需要使用到代码: https://pan.baidu.com/s/1F0KjbwVE8_Tzfwy69Alp-A angular 5 全局错误处理 参考文

成为优秀Angular开发者所需要学习的19件事

一款to-do app基本等同于前端开发的"Hello world".虽然涵盖了创建应用程序的CRUD方面,但它通常只涉及那些框架或库也能做到的皮毛而已. Angular看起来似乎总是在改变和更新 - 但实际上,还是有一些事情仍然保持不变.以下是关于Angular所需要学习的核心概念的概述,以便大家可以正确地利用JavaScript框架. 说到Angular,我们需要学习很多东西,很多人被困在初学者的圈子里,仅仅是因为不知道去哪里搜索或者应该搜索什么关键词.下面我们会说到的这个指南(也

Angular ZoneJS 原理

Zone.js到底是如何工作的? 原文链接: blog.kwintenp.com 如果你阅读过关于Angular 2变化检测的资料,那么你很可能听说过zone.Zone是一个从Dart中引入的特性并被Angular 2内部用来判断是否应该触发变化检测. 如果你去到zone.js的GitHub页面,你会发现它对Zone是这么定义的: Zone是一个在异步任务间保持一致的执行环境.你可以把它理解成是JavaScript VM的线程本地存储. 第一次读到这句话你可能会像我一样摸不着头脑.为了更好的理解

Angular2.0视频教程来了!

各位道友大家好: "Angular2.0视频教程"来了!这是全球第一个完整的Angular 2.0系列视频教程,到目前为止也是唯一的,该系列的视频在优酷和youtube同步播出. 还是大漠穷秋老师,还是熟悉的声音,还是淡淡的小幽默.3年前,大漠老师在慕课网发布了"AngularJS实战" http://www.imooc.com/learn/156 系列视频教程,迄今为止已经有14万人学习,整体评分9.6分.很多道友反馈说,通过学习这门课程找到了心仪的工作,大漠老师

1000行代码实现MVVM (类似Angular1.x.x , Vue)

最近花了近半个多月的时间, 自己纯手工写了一个很小型的类angularjs/vue的mvvm 库. 目前已经用于公司一个项目. 项目托管在github https://github.com/leonwgc/link 也许有许多人觉得如今angularjs , react , vue , knockout ,avalon 等框架/库层出不穷, 为什么还要自己造一个相同(类似)的轮子?  原因如下: 1 . 从最初knockoutjs 到现在用angularjs ,写了不少项目, 一直想自己写一个m

Angular杂谈系列1-如何在Angular2中使用jQuery及其插件

jQuery,让我们对dom的操作更加便捷.由于其易用性和可扩展性,jQuer也迅速风靡全球,各种插件也是目不暇接. 我相信很多人并不能直接远离jQuery去做前端,因为它太好用了,我们以前做的东西大多基于jQuery和它的插件.而且现在Angular2的组件生态还不是很完善,我们在编写Angular的时候也许会想要用到jQuery.本篇文章就简单介绍下在Angular2中使用jQuery 如果你不知道怎么搭建Angular2开发环境,请参考我之前写这篇文章:Angular2入门系列教程1-使用