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', 'john@example.com');

  changeUser() {
    this.currentUser = new User('Alice Smith', 'alice@example.com');
  }
}

通过点击"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', 'john@example.com');
  
  constructor(
    private cdr: ChangeDetectorRef
  ){}

  changeUser() {
    this.currentUser.name = 'Alice Smith';
    this.currentUser.email = 'alice@example.co';
    this.cdr.detectChanges();
  }
}

总结

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

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

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

相关推荐
Domain-zhuo4 分钟前
如何提高webpack的构建速度?
前端·webpack·前端框架·node.js·ecmascript
放逐者-保持本心,方可放逐18 分钟前
SSE 流式场景应用 及 方案总结
javascript·axios·fetch·eventsource
还是大剑师兰特19 分钟前
面试题:ES6模块与CommonJS模块有什么异同?
前端·es6·大剑师
胡西风_foxww34 分钟前
【ES6复习笔记】数值扩展(16)
前端·笔记·es6·扩展·数值
mosen86836 分钟前
uniapp中uni.scss如何引入页面内或生效
前端·uni-app·scss
白云~️36 分钟前
uniappX 移动端单行/多行文字隐藏显示省略号
开发语言·前端·javascript
沙尘暴炒饭38 分钟前
uniapp 前端解决精度丢失的问题 (后端返回分布式id)
前端·uni-app
昙鱼1 小时前
springboot创建web项目
java·前端·spring boot·后端·spring·maven
天天进步20151 小时前
Vue项目重构实践:如何构建可维护的企业级应用
前端·vue.js·重构
小华同学ai1 小时前
vue-office:Star 4.2k,款支持多种Office文件预览的Vue组件库,一站式Office文件预览方案,真心不错
前端·javascript·vue.js·开源·github·office