MST

星途 面试题库

面试题:Angular自定义管道中的纯管道与非纯管道

在Angular自定义管道中,纯管道和非纯管道有什么区别?分别在什么场景下使用?请举例说明在哪些情况下使用非纯管道能够带来更好的效果,同时说明使用非纯管道可能存在的性能问题及如何优化。
34.6万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

纯管道和非纯管道的区别

  1. 纯管道
    • 纯管道只在输入值发生纯变化时才会被调用。所谓纯变化,对于基本数据类型(如字符串、数字、布尔值),只要值改变就会触发;对于对象和数组,只有当引用改变时才会触发。
    • Angular 会对纯管道的输入值进行缓存,若输入值未发生纯变化,Angular 不会重新调用管道,而是使用缓存结果。
  2. 非纯管道
    • 非纯管道在每次 Angular 检测到变化时都会被调用,无论输入值是否真正改变,包括视图渲染、用户交互、数据绑定变化等各种情况。

适用场景

  1. 纯管道适用场景
    • 当管道的计算逻辑相对简单,且输入值变化频率较低时适用。例如格式化日期、货币等。
    • 示例:假设有一个格式化货币的管道 currencyPipe,输入一个数字,返回格式化后的货币字符串。如果输入值不经常改变,使用纯管道就很合适。
    @Pipe({
      name: 'currencyPipe',
      pure: true
    })
    export class CurrencyPipe implements PipeTransform {
      transform(value: number): string {
        return '$' + value.toFixed(2);
      }
    }
    
  2. 非纯管道适用场景
    • 当需要根据应用程序状态的任何变化(不仅仅是输入值变化)来更新输出时使用。例如根据当前用户语言动态格式化日期,因为语言可能随时在应用内切换,即使日期数据本身未改变,也需要重新格式化。
    • 示例:假设要实现一个根据用户当前语言偏好动态格式化日期的管道。
    @Pipe({
      name: 'dynamicDatePipe',
      pure: false
    })
    export class DynamicDatePipe implements PipeTransform {
      constructor(private dateService: DateService) {}
      transform(value: Date): string {
        const lang = this.dateService.getCurrentLang();
        // 根据不同语言格式化日期
        return value.toLocaleDateString(lang);
      }
    }
    

非纯管道带来更好效果的情况

  1. 实时数据展示:例如股票价格实时显示,股票价格数据对象的引用可能不会改变,但价格实时变化,使用非纯管道可以实时更新显示的价格。
  2. 基于应用程序状态变化:如上述根据用户语言偏好动态格式化日期的例子,语言偏好改变时,即使日期数据未变,也需要重新格式化。

非纯管道的性能问题及优化

  1. 性能问题:由于非纯管道在每次 Angular 变化检测时都会被调用,若管道内计算逻辑复杂,会导致性能开销较大,影响应用程序的响应速度。
  2. 优化方法
    • 减少不必要计算:在管道内部,添加逻辑判断,只有在真正需要时才进行复杂计算。例如在动态日期格式化管道中,判断语言是否改变,若未改变则不重新格式化。
    @Pipe({
      name: 'dynamicDatePipe',
      pure: false
    })
    export class DynamicDatePipe implements PipeTransform {
      private lastLang: string;
      constructor(private dateService: DateService) {}
      transform(value: Date): string {
        const lang = this.dateService.getCurrentLang();
        if (this.lastLang === lang) {
          return this.lastFormattedDate;
        }
        this.lastLang = lang;
        const formattedDate = value.toLocaleDateString(lang);
        this.lastFormattedDate = formattedDate;
        return formattedDate;
      }
    }
    
    • 防抖和节流:使用 RxJS 的 debounceTimethrottleTime 操作符来限制管道调用频率。例如在搜索框输入联想功能中,通过防抖减少非纯管道的调用次数。
    import { Component } from '@angular/core';
    import { Observable, fromEvent } from 'rxjs';
    import { debounceTime } from 'rxjs/operators';
    
    @Component({
      selector: 'app-search',
      templateUrl: './search.component.html'
    })
    export class SearchComponent {
      searchText: string;
      constructor() {
        const input$ = fromEvent<HTMLInputElement>(document.getElementById('searchInput'), 'input');
        input$.pipe(
          debounceTime(300)
        ).subscribe(() => {
          // 这里触发非纯管道调用,由于防抖,调用频率降低
        });
      }
    }