MST

星途 面试题库

面试题:Angular管道在复杂数据结构显示中的优化

给定一个包含多层嵌套对象数组的复杂数据结构,例如[{ 'name': 'John', 'grades': [ { 'course': 'Math', 'score': 85 }, { 'course': 'Science', 'score': 90 } ] }, { 'name': 'Jane', 'grades': [ { 'course': 'Math', 'score': 92 }, { 'course': 'Science', 'score': 88 } ] }],你需要在视图中展示每个学生的名字及其每门课程的成绩。为了提高性能,避免不必要的重新渲染,你会如何设计和使用Angular管道来处理这种情况?
37.2万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试
  1. 创建管道

    • 首先,在Angular项目中使用命令行工具创建一个管道,例如ng generate pipe studentGrade。这将生成一个管道类,如下所示:
    import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({
      name:'studentGrade'
    })
    export class StudentGradePipe implements PipeTransform {
      transform(value: any[],...args: unknown[]): any {
        // 这里开始处理数据转换
        let result = [];
        value.forEach(student => {
          student.grades.forEach(grade => {
            result.push({
              name: student.name,
              course: grade.course,
              score: grade.score
            });
          });
        });
        return result;
      }
    }
    
    • 上述管道的作用是将输入的复杂嵌套对象数组,转换为一个更扁平的数组,每个元素包含学生名字、课程名和成绩。这样的结构更适合在视图中展示。
  2. 在模块中声明管道

    • 在相关的模块(如app.module.ts)中,将创建的管道声明到declarations数组中:
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform - browser';
    import { AppComponent } from './app.component';
    import { StudentGradePipe } from './student - grade.pipe';
    
    @NgModule({
      declarations: [
        AppComponent,
        StudentGradePipe
      ],
      imports: [
        BrowserModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule {}
    
  3. 在视图中使用管道

    • 假设在组件的模板文件(如app.component.html)中有如下代码:
    <ul>
      <li *ngFor="let item of students | studentGrade">
        {{item.name}} - {{item.course}}: {{item.score}}
      </li>
    </ul>
    
    • 这里students是组件类中包含复杂嵌套对象数组的数据属性。通过管道studentGrade的转换,在视图中遍历展示每个学生的名字及其每门课程的成绩。
  4. 优化性能避免不必要的重新渲染

    • 为了避免不必要的重新渲染,可以使用pure管道。Angular中的管道默认是pure的,这意味着只有当输入值是原始类型(如字符串、数字等)发生变化,或者引用类型(如对象、数组)的引用发生变化时,管道才会重新执行。
    • 在我们的场景中,如果students数组的引用没有发生变化,即使数组内部的数据改变了,管道也不会重新执行。如果需要在数组内部数据变化时也执行管道,可以将管道设置为impure。但这样会增加性能开销,因为Angular会更频繁地检查管道是否需要重新执行。
    • 如果要保持pure管道且希望在数组内部数据变化时进行更新,可以使用ChangeDetectorRef。例如,在组件类中注入ChangeDetectorRef,并在数据变化时手动调用detectChanges方法。但在大多数情况下,通过合理设计数据结构,保持pure管道的默认行为可以在一定程度上优化性能,避免不必要的重新渲染。
    import { Component, ChangeDetectorRef } from '@angular/core';
    
    @Component({
      selector: 'app - component',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      students = [
        { 'name': 'John', 'grades': [ { 'course': 'Math','score': 85 }, { 'course': 'Science','score': 90 } ] },
        { 'name': 'Jane', 'grades': [ { 'course': 'Math','score': 92 }, { 'course': 'Science','score': 88 } ] }
      ];
    
      constructor(private cdr: ChangeDetectorRef) {}
    
      updateStudentGrade() {
        // 假设这里更新了学生成绩
        this.students[0].grades[0].score = 90;
        this.cdr.detectChanges();
      }
    }
    
    • 但通常情况下,尽量避免直接修改数据结构,而是通过创建新的数据结构来触发pure管道的重新执行,这样可以更好地利用Angular的变化检测机制优化性能。例如:
    updateStudentGrade() {
      let newStudents = [...this.students];
      newStudents[0].grades[0].score = 90;
      this.students = newStudents;
    }
    
    • 这样,students数组的引用发生了变化,pure管道会重新执行,从而更新视图,同时也避免了不必要的频繁重新渲染。