Чому Pipes в Angular перевершують функції для трансформації даних

“А може, замість цього використаємо пайпи?” — побачив я цей коментар у запиті на злиття, який подав лише дві години тому. Я ще не зовсім розумів усі переваги пайпів, і перша моя думка була: “Чому б просто не створити утилітну функцію?” Це зацікавило мене, і я відчув бажання розібратися глибше.
Без сумнівів, я почав шукати інформацію в Google, щоб дізнатися більше.

Поширена проблема — що не так з простою функцією

Розглянемо приклад функції, яка просто робить першу літеру імені великою.

import { Component } from '@angular/core';  
import { nameList } from './random-names-list';  

@Component({  
 selector: 'my-app',  
 template: `  
 \  
 \
    `,    styleUrls: ['./app.component.css'],  
})   
export class AppComponent {  
 names = [];  
 count = 0;  
 capitalize(name: string) {  
   console.log('Функція capitalize виконана: ', ++this.count);  
   return name.charAt(0).toUpperCase() + name.slice(1);  
 }  
 addRandomUser() {  
   const randomName = nameList[Math.floor(Math.random() * nameList.length)];  
   this.names.push(randomName);  
 }  
}  

Проблема вирішена, так? Ну, давайте подивимося на консоль, щоб дізнатися, скільки разів насправді була викликана функція, коли ми додали 3 користувачів.

pic

Вау!! Вона була викликана 12 разів, але чому так? Це через те, як працює система виявлення змін в Angular.

Аналіз виконання

Початковий стан

  • Коли компонент вперше завантажується, names — порожній масив.
  • Викликів функції capitalize() не відбувається, оскільки в масиві names немає елементів.

Перший клік кнопки

  • addRandomUser() додає одне ім’я до масиву names (names.length = 1).
  • Angular обробляє виявлення змін:
    • Директива *ngFor перебирає оновлений масив names (1 елемент).
    • Функція capitalize викликається один раз.

Загальна кількість викликів: 1

Другий клік кнопки

  • addRandomUser() додає ще одне ім’я до масиву names (names.length = 2).
  • Angular обробляє виявлення змін:
    • Директива *ngFor перебирає оновлений масив names (2 елементи).
    • Функція capitalize викликається два рази (по одному для кожного імені в масиві).

Загальна кількість викликів: 1 (попереднє) + 2 = 3

Третій клік кнопки

  • addRandomUser() додає ще одне ім’я до масиву names (names.length = 3).
  • Angular обробляє виявлення змін:
    • Директива *ngFor перебирає оновлений масив names (3 елементи).
    • Функція capitalize викликається три рази (по одному для кожного імені в масиві).

Загальна кількість викликів: 3 (попереднє) + 3 = 6

Але ось у чому секрет: Angular не зупиняється на оцінці лише одного циклу виявлення змін.
Він робить додаткові проходи, щоб забезпечити стабільність і правильність інтерфейсу користувача, що призводить до 6 додаткових викликів, в результаті чого загальна кількість викликів становить 12.

  • Це дуже неефективно. Уявіть, що у вас є десятки тисяч користувачів і ви використовуєте цю утилітарну функцію.
  • Це призведе до дублювання коду, адже вам, можливо, знадобиться та сама функція capitalize, щоб відобразити інші дані.
  • Навіть якщо ви перемістите цей код в сервіс, проблема залишиться.

Ось тут і з’являється Pipe. Він забезпечує повторне використання і не впливає на продуктивність.
Ось той самий код, але з використанням pipes.

// файл capitalize.pipe.ts  

import { Pipe, PipeTransform } from '@angular/core';  

@Pipe({  
 name: 'capitalize',  
})  
export class CapitalizePipe implements PipeTransform {  
 count = 0;  

 transform(name: string): string {  
 console.log('Функція capitalize виконана: ', ++this.count);  
 return name.charAt(0).toUpperCase() + name.slice(1);  
 }  
}
// файл app.component.ts  

import { Component} from '@angular/core';  
import { nameList } from './random-names-list';  

@Component({  
 selector: 'my-app',  
 template: `  
 \  
 \
{{ name | capitalize }}\    \    \ДОДАТИ КОРИСТУВАЧА\    `,    styleUrls: ['./app.component.css'],   })   export class AppComponent {    names = [];       addRandomUser() {    const randomName = nameList[Math.floor(Math.random() * nameList.length)];    this.names.push(randomName);    }   }  

pic

Тепер можна побачити, що кількість викликів зменшилася з 6 до 3.
Якщо ви додасте 7 користувачів до списку, то при використанні функції буде здійснено 56 викликів, а при використанні pipe — лише 7.

“Звісно, ми можемо використати pipes для цього” — відповів я на коментар і внес зміни.

Якщо хочете більше таких історій, ставте лайк і підписуйтесь 🙂

Перекладено з: Why Angular Pipes Outshine Functions for Data Transformation

Leave a Reply

Your email address will not be published. Required fields are marked *