Angular系列教程之变更检测与性能优化

文章目录

前言

Angular 除了默认的变化检测机制,也提供了ChangeDetectionStrategy.OnPush,用 OnPush 可以跳过某个组件或者某个父组件以及它下面所有子组件的变化检测。

在本文中,我们将探讨Angular中的变更检测机制,并通过示例代码来说明其工作原理。

变更检测的原理

当我们在 model 中改变数据时,框架层需要知道:

  • model 哪里发生了改变

  • view 中哪里需要更新

当Angular应用运行时,它会周期性地检查组件及其绑定属性的状态是否发生了变化,并相应地更新视图。这个过程称为变更检测。

整个angular app 是个组件树,不可能任意一个组件中的数据发生变化,所有的组件都更新,性能比较低。

为此,Angular提供了两种变更检测策略:默认的脏检查OnPush策略

脏检查

脏检查是Angular默认采用的变更检测策略。它通过比较对象的旧值和新值来检测变化。当组件中的某个属性发生变化时,Angular会标记这个组件为"脏",并触发变更检测过程。在变更检测过程中,Angular会递归遍历组件树,检查每个组件及其绑定属性是否发生了变化,并更新相应的视图。

虽然脏检查是一种灵活的变更检测策略,但它也可能导致性能问题。因为每次变更检测都需要遍历整个组件树,当应用规模较大时,性能开销会变得非常显著。

OnPush策略

为了解决脏检查可能带来的性能问题,Angular引入了OnPush策略。这种策略通过明确告诉Angular哪些组件是纯粹的(pure)来提高性能。纯组件只在它们的输入属性发生变化时才被视为"脏",从而触发变更检测。

要使用OnPush策略,我们需要将组件的changeDetection属性设置为ChangeDetectionStrategy.OnPush。此外,我们还需要注意,输入属性必须是不可变(immutable)的,即不能直接修改其值,而是应该返回一个新的对象。

示例代码

下面是一个简单的示例,演示了如何使用Angular的变更检测机制。假设我们有一个名为UserComponent的组件,其中包含一个名为user的输入属性。

typescript 复制代码
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-user',
  template: `
    <div>
      <h2>{{ user.name }}</h2>
      <p>{{ user.email }}</p>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UserComponent {
  @Input() user: User;
}

在上面的代码中,我们使用了changeDetection: ChangeDetectionStrategy.OnPush来启用OnPush策略。这意味着当user输入属性发生变化时,才会触发变更检测。

除此之外,我们还需要定义一个User类来表示用户对象:

typescript 复制代码
export class User {
  constructor(public name: string, public email: string) {}
}

在父组件中,我们可以随时修改user属性的值,并观察变更检测的效果:

typescript 复制代码
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <app-user [user]="currentUser"></app-user>
    <button (click)="changeUser()">Change User</button>
  `,
})
export class AppComponent {
  currentUser: User = new User('John Doe', '[email protected]');

  changeUser() {
    this.currentUser = new User('Alice Smith', '[email protected]');
  }
}

通过点击"Change User"按钮,我们可以看到视图中显示的用户名和邮箱地址实时更新。

此外,我们还可以借助ChangeDetectorRef对象,主动触发Angular的变更检测。示例代码如下:

typescript 复制代码
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <app-user [user]="currentUser"></app-user>
    <button (click)="changeUser()">Change User</button>
  `,
})
export class AppComponent {
  currentUser: User = new User('John Doe', '[email protected]');
  
  constructor(
    private cdr: ChangeDetectorRef
  ){}

  changeUser() {
    this.currentUser.name = 'Alice Smith';
    this.currentUser.email = '[email protected]';
    this.cdr.detectChanges();
  }
}

总结

变更检测是Angular框架的核心功能之一。通过脏检查和OnPush策略,Angular能够自动追踪组件及其绑定属性的变化,并更新相应的视图。

尽管脏检查是默认的检测策略,但在性能要求较高的情况下,使用OnPush策略可以明显降低Angular的变更检测次数,从而显著提升应用的性能。

希望本文对您理解Angular的变更检测机制有所帮助!

相关推荐
三翼鸟数字化技术团队10 分钟前
Vue自定义指令最佳实践教程
前端·vue.js
Jasmin Tin Wei38 分钟前
蓝桥杯 web 学海无涯(axios、ecahrts)版本二
前端·蓝桥杯
圈圈编码1 小时前
Spring Task 定时任务
java·前端·spring
猿榜1 小时前
js逆向-喜某拉雅Xm-Sign参数解密
javascript
转转技术团队1 小时前
代码变更暗藏危机?代码影响范围分析为你保驾护航
前端·javascript·node.js
Mintopia1 小时前
Node.js高级实战:自定义流与Pipeline的高效数据处理 ——从字母生成器到文件管道的深度解析
前端·javascript·node.js
Mintopia1 小时前
Three.js深度解析:InstancedBufferGeometry实现动态星空特效 ——高效渲染十万粒子的底层奥秘
前端·javascript·three.js
北凉温华1 小时前
强大的 Vue 标签输入组件:基于 Element Plus 的 ElTagInput 详解
前端
随笔记1 小时前
Flex布局下,label标签设置宽度依旧对不齐,完美解决(flex-shrink属性)
javascript·css·vue.js
原生高钙1 小时前
LLM大模型对话框实践:大文件的分片上传
前端