MST

星途 面试题库

面试题:Angular内置结构性指令的性能优化策略

在大型Angular应用中,结构性指令(如NgFor、NgIf等)的频繁操作可能导致性能瓶颈。请详细说明针对这些内置结构性指令的性能优化策略,包括但不限于如何利用trackBy函数优化NgFor的性能,以及如何避免因NgIf频繁创建和销毁组件带来的性能损耗。并结合实际代码示例进行说明。
19.8万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

1. 利用 trackBy 函数优化 NgFor 的性能

  • 原理NgFor 在渲染列表时,默认会基于对象引用或数组索引来跟踪每个项目。当列表发生变化时,Angular 会重新渲染整个列表,即便只有部分项目真正改变。trackBy 函数允许开发者提供一个自定义的跟踪函数,让 Angular 能够更高效地识别变化的项目,从而只更新真正发生变化的部分,提升性能。
  • 示例代码
<ul>
  <li *ngFor="let item of items; trackBy: trackByFn">{{item.name}}</li>
</ul>
import { Component } from '@angular/core';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.css']
})
export class ExampleComponent {
  items = [
    { id: 1, name: 'Item 1' },
    { id: 2, name: 'Item 2' },
    { id: 3, name: 'Item 3' }
  ];

  trackByFn(index: number, item: any) {
    return item.id; // 以 item 的 id 作为跟踪依据
  }
}

2. 避免因 NgIf 频繁创建和销毁组件带来的性能损耗

  • 策略一:使用 NgSwitch 代替频繁切换的 NgIf
    • 原理NgIf 会在条件为 false 时完全销毁 DOM 及其内部组件,条件为 true 时重新创建。而 NgSwitch 会保留所有可能的分支,通过切换显示状态来实现不同视图的展示,避免了频繁的创建和销毁。
    • 示例代码
<div [ngSwitch]="condition">
  <div *ngSwitchCase="'value1'">
    <app-component1></app-component1>
  </div>
  <div *ngSwitchCase="'value2'">
    <app-component2></app-component2>
  </div>
  <div *ngSwitchDefault>
    <app-component3></app-component3>
  </div>
</div>
import { Component } from '@angular/core';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.css']
})
export class ExampleComponent {
  condition = 'value1';
}
  • 策略二:缓存 NgIf 内部组件状态
    • 原理:可以使用 @Output@Input 来保存和恢复组件的状态,这样在 NgIf 销毁和重新创建组件时,能够快速恢复到之前的状态,减少初始化开销。
    • 示例代码子组件(child.component.ts)
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent {
  @Input() data: any;
  @Output() dataChange = new EventEmitter<any>();

  updateData(newData: any) {
    this.data = newData;
    this.dataChange.emit(newData);
  }
}

父组件(parent.component.html)

<button (click)="toggle()">Toggle</button>
<ng-container *ngIf="isVisible">
  <app-child [data]="cachedData" (dataChange)="cachedData = $event"></app-child>
</ng-container>

父组件(parent.component.ts)

import { Component } from '@angular/core';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {
  isVisible = true;
  cachedData = { initial: 'value' };

  toggle() {
    this.isVisible =!this.isVisible;
  }
}