返回顶部
首页 > 资讯 > 精选 >Angular中的Change Detection机制怎么实现
  • 952
分享到

Angular中的Change Detection机制怎么实现

2023-07-04 19:07:49 952人浏览 独家记忆
摘要

这篇文章主要介绍“angular中的Change Detection机制怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Angular中的Change Detection机制怎么实现”文章能帮

这篇文章主要介绍“angular中的Change Detection机制怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Angular中的Change Detection机制怎么实现”文章能帮助大家解决问题。

什么是 Change Detection ?

在应用的开发过程中,state 代表需要显示在应用上的数据。当 state 发生变化时,往往需要一种机制来检测变化的 state 并随之更新对应的界面。这个机制就叫做 Change Detection 机制。

WEB 开发中,更新应用界面其实就是对 DOM 树进行修改。由于 DOM 操作是昂贵的,所以一个效率低下的 Change Detection 会让应用的性能变得很差。因此,框架在实现 Change Detection 机制上的高效与否,很大程度上决定了其性能的好坏。

Change Detection 是如何实现的

Angular 可以检测组件数据何时更改,然后自动重新渲染视图以反映该更改。但是在像点击按钮这样的低级事件之后,它怎么能做到这一点呢?

通过 Zone , Angular 能够实现自动的触发 Change Detection 机制

Zone 是什么呢?简而言之,Zone 是一个执行上下文(execution context),可以理解为一个执行环境。与常见的浏览器执行环境不同,在这个环节中执行的所有异步任务都被称为 Task ,Zone 为这些 Task 提供了一堆的钩子(hook),使得开发者可以很轻松的「监控」环境中所有的异步任务。

题外话:由于 Angular 极力的推崇使用可观察对象(Observable),如果完全的基于 Observable 来开发应用,可以代替 Zone 来实现追踪调用栈的功能,且性能还比使用 Zone 会稍好一些。

  // Angular 在 v5.0.0-beta.8 起可以通过配置不使用 Zone   import { platfORMBrowser } from '@angular/platform-browser';  platformBrowser().bootstrapModuleFactory(AppModuleNgFactory, { ngZone: 'noop' });

覆盖浏览器默认机制

Angular 在启动时会重写浏览器 low-level api,例如addEventListener,它是用于注册所有浏览器事件的浏览器函数,包括点击处理。Angular 将替换addEventListener为与此等效的新版本:

// this is the new version of addEventListener                                    function addEventListener(eventName, callback) {     // call the real addEventListener                    callRealAddEventListener(eventName, function() {         //first call the original callback                      callback(...);        // and then run Angular-specific functionality        var changed = angular.runChangeDetection();        if (changed) {            angular.reRenderUIPart();        }    });}

新的addEventListener为任何事件处理程序添加了更多功能:不仅调用了注册的回调,而且 Angular 有机会运行更改检测并更新 UI。

支持浏览器异步 API

修补了以下常用浏览器机制以支持更改检测:

  • 所有浏览器事件(单击、鼠标悬停、按键等)

  • setTimeout()setInterval()

  • ajax Http 请求

事实上,Zone.js 修补了许多其他浏览器 API,以透明地触发 Angular 更改检测,例如 websockets。

这种机制的一个限制是,如果由于某种原因 Zone.js 不支持的异步浏览器 API,则不会触发更改检测。例如,IndexedDB 回调就是这种情况。

默认的变更检测机制是如何工作的?

每个 Angular 组件都有一个关联的变更检测器,它是在应用程序启动时创建的。例如:

@Component({    selector: 'todo-item',    template: `<span class="todo noselect"        (click)="onToggle()">{{todo.owner.firstname}} - {{todo.description}}       - completed: {{todo.completed}}</span>`})export class TodoItem {    @Input()    todo:Todo;    @Output()    toggle = new EventEmitter<Object>();    onToggle() {        this.toggle.emit(this.todo);    }}

该组件将接收一个 Todo 对象作为输入,并在 todo 状态被切换时发出一个事件。

export class Todo {    constructor(public id: number,         public description: string,         public completed: boolean,         public owner: Owner) {    }}

我们可以看到 Todo 有一个属性owner,它本身就是一个具有两个属性的对象:firstnamelastname

变更检测器是什么样的?

我们实际上可以在运行时看到变化检测器的样子!要查看它,只需在 Todo 类中添加一些代码以在访问某个属性时触发断点。

当断点命中时,我们可以遍历堆栈跟踪并查看变化检测:

Angular中的Change Detection机制怎么实现

这个方法一开始可能看起来很奇怪,所有变量都奇怪命名。但是通过深入研究,我们注意到它在做一些非常简单的事情:对于模板中使用的每个表达式,它会将表达式中使用的属性的当前值与该属性的先前值进行比较。

如果前后的属性值不同,就会设置isChanged 为true,就这样!差不多,它是通过使用一个名为looseNotIdentical() 的方法来比较值。

那么嵌套对象owner呢?

我们可以在更改检测器代码中看到 owner 嵌套对象的属性也正在检查差异。但只比较 firstname 属性,而不是 lastname 属性。这是因为组件template中没有使用lastname!同样,Todo 的顶级 id 属性也没有出于相同的原因进行比较。

有了这个,我们可以有把握地说:

默认情况下,Angular Change Detection 通过检查模板表达式的值是否已更改来工作。

我们还可以得出结论:

默认情况下,Angular 不做深度对象比较来检测变化,它只考虑模板使用的属性

为什么默认情况下更改检测会这样工作?

Angular 的主要目标之一是更加透明和易于使用,因此框架用户不必费尽心思调试框架并了解内部机制即可有效地使用它。

如果 Angular 默认更改检测机制基于组件输入的参考比较而不是默认机制,那会是什么情况?即使是像 TODO 应用程序这样简单的东西也很难构建:开发人员必须非常小心地创建一个新的 Todo,而不是简单地更新属性。

OnPush 变化检测策略

如果你觉得默认模式影响了性能,我们也可以自定义 Angular 更改检测。将组件更改检测策略更新为OnPush

@Component({    selector: 'todo-list',    changeDetection: ChangeDetectionStrategy.OnPush,    template: ...})export class TodoList {    ...}

现在让我们在应用程序中添加几个按钮:一个是通过直接改变列表的第一项来切换列表的第一项,另一个是向整个列表添加一个 Todo。代码如下所示:

@Component({    selector: 'app',    template: `<div>                    <todo-list [todos]="todos"></todo-list>               </div>               <button (click)="toggleFirst()">Toggle First Item</button>               <button (click)="addTodo()">Add Todo to List</button>`})export class App {    todos:Array = initialData;    constructor() {    }    toggleFirst() {        this.todos[0].completed = ! this.todos[0].completed;    }    addTodo() {        let newTodos = this.todos.slice(0);        newTodos.push( new Todo(1, "TODO 4",             false, new Owner("John", "Doe")));        this.todos = newTodos;    }}

现在让我们看看这两个新按钮的行为:

  • 第一个按钮“切换第一项”不起作用!这是因为该toggleFirst()方法直接改变了列表中的一个元素。
    TodoList无法检测到这一点,因为它的输入参考todos没有改变

  • 第二个按钮确实有效!请注意,该方法addTodo()创建了 todo 列表的副本,然后将项目添加到副本中,最后将 todos 成员变量替换为复制的列表。这会触发更改检测,因为组件检测到其输入中的参考更改:它收到了一个新列表!

  • 在第二个按钮中,直接改变 todos 列表是行不通的!我们真的需要一个新的清单。

OnPush只是通过引用比较输入吗?

情况并非如此。当使用 OnPush 检测器时,框架将在 OnPush 组件的任何输入属性更改、触发事件或 Observable 触发事件时检查

尽管允许更好的性能,但OnPush如果与可变对象一起使用,则使用会带来很高的复杂性成本。它可能会引入难以推理和重现的错误。但是有一种方法可以使使用OnPush可行。

使用 Immutable.js 简化 Angular 应用程序的构建

如果我们只使用不可变对象和不可变列表来构建我们的应用程序,则可以OnPush透明地在任何地方使用,而不会遇到更改检测错误的风险。这是因为对于不可变对象,修改数据的唯一方法是创建一个新的不可变对象并替换之前的对象。使用不可变对象,我们可以保证:

  • 新的不可变对象将始终触发OnPush更改检测

  • 我们不会因为忘记创建对象的新副本而意外创建错误,因为修改数据的唯一方法是创建新对象

实现不可变的一个不错的选择是使用Immutable.js库。该库为构建应用程序提供了不可变原语,例如不可变对象(映射)和不可变列表。

避免变更检测循环:生产与开发模式

Angular 更改检测的重要属性之一是,与 AngularJs 不同,它强制执行单向数据流:当我们的控制器类上的数据更新时,更改检测运行并更新视图。

如何在 Angular 中触发变更检测循环?

一种方法是如果我们使用生命周期回调。例如,在TodoList组件中,我们可以触发对另一个组件的回调来更改其中一个绑定:

ngAfterViewChecked() {    if (this.callback && this.clicked) {        console.log("changing status ...");        this.callback(Math.random());    }}

控制台中将显示一条错误消息:

EXCEPTION: Expression '{{message}} in App@3:20' has changed after it was checked

仅当我们在开发模式下运行 Angular 时才会抛出此错误消息。如果我们启用生产模式会发生什么?在生产模式下,错误不会被抛出,问题也不会被发现。

在开发阶段始终使用开发模式会更好,因为这样可以避免问题。这种保证是以 Angular 总是运行两次变更检测为代价的,第二次检测这种情况。在生产模式下,变更检测只运行一次。

打开/关闭变化检测,并手动触发它

在某些特殊情况下,我们确实想要关闭更改检测。想象一下这样一种情况,大量数据通过 webSocket后端到达。我们可能只想每 5 秒更新一次 UI 的某个部分。为此,我们首先将更改检测器注入到组件中:

constructor(private ref: ChangeDetectorRef) {    ref.detach();    setInterval(() => {      this.ref.detectChanges();    }, 5000);  }

正如我们所看到的,我们只是分离了变化检测器,这有效地关闭了变化检测。然后我们只需每 5 秒通过调用手动触发它detectChanges()

现在让我们快速总结一下我们需要了解的关于 Angular 变更检测的所有内容:它是什么,它是如何工作的以及可用的主要变更检测类型是什么。

概括

Angular 更改检测是一个内置的框架功能,可确保组件数据与其 html 模板视图之间的自动同步。

更改检测的工作原理是检测常见的浏览器事件,如鼠标点击、HTTP 请求和其他类型的事件,并确定每个组件的视图是否需要更新。

变更检测有两种类型:

  • 默认更改检测:Angular 通过比较事件发生前后的所有模板表达式值来决定是否需要更新视图,用于组件树的所有组件

  • OnPush 更改检测:这通过检测是否已通过组件输入或使用异步管道订阅的 Observable 将某些新数据显式推送到组件中来工作

Angular默认更改检测机制实际上与 AngularJs 非常相似:它比较浏览器事件之前和之后模板表达式的值,以查看是否有更改。它对所有组件都这样做。但也有一些重要的区别:

一方面,没有变化检测循环,也没有 AngularJs 中命名的摘要循环。这允许仅通过查看其模板和控制器来推理每个组件。

另一个区别是,由于变化检测器的构建方式,检测组件变化的机制要快得多。

最后,与 AngularJs 不同的是,变化检测机制是可定制的。

关于“Angular中的Change Detection机制怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。

--结束END--

本文标题: Angular中的Change Detection机制怎么实现

本文链接: https://lsjlt.com/news/347122.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Angular中的Change Detection机制怎么实现
    这篇文章主要介绍“Angular中的Change Detection机制怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Angular中的Change Detection机制怎么实现”文章能帮...
    99+
    2023-07-04
  • 浅析Angular中的Change Detection机制
    // Angular 在 v5.0.0-beta.8 起可以通过配置不使用 Zone import { platformBrowser } from '@angular/platform-browser'; p...
    99+
    2023-05-14
    Change Detection 前端 Angular.js
  • Angular中Change Detection的示例分析
    这篇文章主要介绍Angular中Change Detection的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!ChangeDection检测程序内部状态,然后反映到UI上。引起状态变化,引发检查的驱动源:E...
    99+
    2023-06-06
  • 描述Netdata中利用Anomaly Detection的机制
    Netdata中利用Anomaly Detection的机制通过监视系统的性能指标,并检测异常行为或异常情况。它使用一系列算法和模型来分析系统性能数据,以便及时发现潜在的问题或异常行为。 Netdata中的Anomaly Detection...
    99+
    2024-06-03
    zabbix
  • Angular的ChangeDetection机制实现详解
    目录什么是 Change Detection Change Detection 是如何实现的覆盖浏览器默认机制支持浏览器异步 API默认的变更检测机制是如何工作的?变更检测器是什么样...
    99+
    2022-11-13
    Angular Change Detection机制 Angular Change Detection
  • angular的样式隔离实现机制是什么
    本篇内容主要讲解“angular的样式隔离实现机制是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“angular的样式隔离实现机制是什么”吧!angular...
    99+
    2024-04-02
  • angular怎么进行样式隔离?实现机制详解
    总结我们首先介绍了css 的属性选择器和后代选择器。通过分析angular 生成的html 和css 代码,发现angular 的样式隔离功能,完全是基于这两个内容实现的。接下来,分析了::ng-deep 有时候生效,有时候有不生效的原因。...
    99+
    2023-05-14
    Angular
  • angular中的动画怎么实现
    这篇文章主要介绍了angular中的动画怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇angular中的动画怎么实现文章都会有所收获,下面我们一起来看看吧。状态1、什么...
    99+
    2024-04-02
  • angular的变更机制是什么
    本篇内容主要讲解“angular的变更机制是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“angular的变更机制是什么”吧!一、什么是变更检测概括: 一种...
    99+
    2024-04-02
  • Java中怎么实现SPI机制
    Java中怎么实现SPI机制,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。2 什么是SPI机制SPI是Service Provider Interface 的简...
    99+
    2023-06-16
  • Java中的回调机制怎么实现
    本篇内容介绍了“Java中的回调机制怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!模块间的调用在一个应用系统中,无论使用何种语言开发...
    99+
    2023-06-02
  • NoSQL中的缓存机制怎么实现
    在NoSQL中,缓存机制可以通过以下几种方式实现: 使用内存缓存:将数据存储在内存中,减少读写操作的时间。可以使用缓存库如Red...
    99+
    2024-05-07
    NoSQL
  • JAVA中怎么实现反射机制
    这期内容当中小编将会给大家带来有关JAVA中怎么实现反射机制,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。JAVA反射机制定义:  JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属...
    99+
    2023-06-17
  • PHP中怎么实现缓存机制
    这篇文章给大家介绍PHP中怎么实现缓存机制,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。普遍缓存技术数据缓存:这里所说的数据缓存是指数据库查询PHP缓存机制,每次访问页面的时候,都会先检测相应的缓存数据是否存在,如果不...
    99+
    2023-06-17
  • 怎么理解PostgreSQL Locks中的The Deadlock Detection Algorithm
    这篇文章主要讲解了“怎么理解PostgreSQL Locks中的The Deadlock Detection Algorithm”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,...
    99+
    2024-04-02
  • angular中怎么实现输入与输出
    本篇文章给大家分享的是有关angular中怎么实现输入与输出,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。组件的输入angular允许使用两种...
    99+
    2024-04-02
  • Angular DOM中更新机制的示例分析
    这篇文章主要介绍了Angular DOM中更新机制的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。由模型变化触发的 DOM 更新是所有前端框架的重要功能(注:即保持 ...
    99+
    2023-06-15
  • nodejs中stream和pipe机制怎么实现
    这篇文章给大家分享的是有关nodejs中stream和pipe机制怎么实现的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。通过nodeschool学习streamnodeschoo...
    99+
    2024-04-02
  • python中的垃圾回收机制怎么实现
    这篇文章主要讲解了“python中的垃圾回收机制怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“python中的垃圾回收机制怎么实现”吧!python采用的是引用计数机制为主,标记-清...
    99+
    2023-06-28
  • Java中的synchronized锁膨胀机制怎么实现
    这篇文章主要讲解了“Java中的synchronized锁膨胀机制怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中的synchronized锁膨胀机制怎么实现”吧!synch...
    99+
    2023-06-30
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作