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的变更检测机制有所帮助!

相关推荐
吃杠碰小鸡28 分钟前
commitlint校验git提交信息
前端
虾球xz1 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇1 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒1 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员1 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐1 小时前
前端图像处理(一)
前端
程序猿阿伟2 小时前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒2 小时前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪2 小时前
AJAX的基本使用
前端·javascript·ajax
力透键背2 小时前
display: none和visibility: hidden的区别
开发语言·前端·javascript