Встроенная функция debounce в Angular 2+: поиск решения

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для повышения эффективности приложений Angular, можно воспользоваться оператором RxJS debounceTime. Он позволяет ограничить частоту событий ввода в FormControl с помощью valueChanges:

JS
Скопировать код
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

// Создание элемента управления
const inputControl = new FormControl();

// Применение debounce
inputControl.valueChanges
  .pipe(debounceTime(300), distinctUntilChanged())
  .subscribe(debouncedValue => {
    // Результат: ввод данных с задержкой
    console.log(debouncedValue);
  });

Параметр debounceTime(300) задаёт задержку в 300 мс, после истечения которой возвращается последнее введённое значение.

Кинга Идем в IT: пошаговый план для смены профессии

Углубляемся в основы

Работа с API-запросами или данными пользователя бывает сложной: поток событий может замедлить работу приложения и увеличить нагрузку на систему. В этом случае на помощь придёт debounce, который задерживает обработку действия до истечения определенного периода бездействия. Особенно ценно это для фреймворка Angular и работы с формами.

Управление событиями вне Angular

Хотите повысить производительность? Пригодится ngZone.runOutsideAngular() — это позволит выполнять действия, минуя систему отслеживания изменений Angular, что ускорит работу вашего приложения. Вот как это можно сделать:

typescript
Скопировать код
import { NgZone } from '@angular/core';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

constructor(private zone: NgZone, private elRef: ElementRef) {}

ngAfterViewInit() {
  this.zone.runOutsideAngular(() => {
    fromEvent(this.elRef.nativeElement, 'input')
      .pipe(debounceTime(300))
      .subscribe(event => {
        this.zone.run(() => {
          // Обработка событий начинается здесь...
        });
      });
  });
}

Ручное обнаружение изменений

Иногда возникает необходимость запускать обнаружение изменений в Angular вручную для экономии ресурсов. В таком случае удобно использовать ChangeDetectorRef с его методом detectChanges():

typescript
Скопировать код
import { ChangeDetectorRef } from '@angular/core';

constructor(private cdr: ChangeDetectorRef) {}

// В какой-то части вашего компонента...
this.cdr.detectChanges(); // Указываем Angular проверить изменения

Если требуется запустить обнаружение изменений для всего приложения, используйте ApplicationRef.tick(). Однако, следует быть осторожным: чрезмерное использование может негативно сказаться на производительности.

Оборачиваем debounce в готовое решение

Чтобы обеспечить переиспользование, стоит подумать о создании директивы или сервиса, которые бы инкапсулировали логику работы debounce. Директива подойдёт для шаблонных форм или для прямого применения к HTML-элементам:

typescript
Скопировать код
import { Directive, ElementRef, OnInit, OnDestroy, Output, EventEmitter } from '@angular/core';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

@Directive({
  selector: '[appDebounceClick]'
})
export class DebounceClickDirective implements OnInit, OnDestroy {
  @Output() debounceClick = new EventEmitter();
  private clickObservable$;

  constructor(private elementRef: ElementRef) {}

  ngOnInit() {
    this.clickObservable$ = fromEvent(this.elementRef.nativeElement, 'click')
      .pipe(debounceTime(300))
      .subscribe(e => this.debounceClick.emit(e));
  }

  ngOnDestroy() {
    this.clickObservable$.unsubscribe();
  }
}

Применив директиву [appDebounceClick] к элементу, вы реализуете debounce без написания дополнительного кода в компонентах.

Не забывайте отписываться от observable после уничтожения вашего компонента, чтобы избежать утечек памяти.

Визуализация

Вообразите переполненный вокзал (🚉), где поезда (🚆) — это функциональные вызовы, следующие один за другим. Нам нужен именно тот поезд, который прибудет после периода бездействия, а не первый попавшийся:

Markdown
Скопировать код
| Ситуация             | Визуализация        |
|----------------------|---------------------|
| Постоянные вызовы    | 🚆🚆🚆🚆🚆🚆🚆        |
| Применение Debounce  | 🚆🚆🚆🕒...🚆        |

Debounce в Angular — это своего рода табло расписания (📅), которое сигнализирует (⏰) только о последнем прибывшем поезде после паузы:

typescript
Скопировать код
// В Angular это выглядит так:
searchInput.valueChanges.pipe(
  debounceTime(300) // Подождем 300 мс
).subscribe(value => {
  // Обрабатываем только 'поезд', который прибыл после паузы
});

Ключевые моменты:

  • debounceTime(300) позволяет провести действие только после прошедших 300 мс молчания.
  • Это подобно диспетчеру на вокзале, контролирующему поток поездов, чтобы избегать чрезмерной нагрузки.

Дополнения и задачи

Использование debounce может быть полезным, но требует обдуманного применения. Если нужно гарантировать выполнение действия с определенной периодичностью, сочетайте debounce с throttling:

typescript
Скопировать код
import { throttleTime } from 'rxjs/operators';

// Пример использования троттлинга
inputControl.valueChanges
  .pipe(throttleTime(300))
  .subscribe(throttledValue => {
    // Здесть появляется троттлированное событие
  });

Если вы столкнулись с множеством последовательных одинаковых значений, используйте distinctUntilChanged. Этот оператор не пропускает подряд идущие одинаковые значения и хорошо сочетается с debounce:

typescript
Скопировать код
inputControl.valueChanges
  .pipe(debounceTime(300), distinctUntilChanged())
  .subscribe(value => {
    // Работаем только с уникальными и отложенными значениями
  });

Владение механизмами контроля за изменениями, умение повышать производительность через ngZone и знание различных операторов RxJS превратят вас в настоящего мастера обработки данных в Angular.

Полезные материалы

  1. Angular – оператор RxJS debounceTimeОфициальная документация Angular по оператору debounce.
  2. RxJS – debounceTime — подробная документация RxJS.
  3. Learn JavaScript, Angular, React, RxJS, TypeScript — данная ссылка поможет разобраться с RxJS debounceTime и distinctUntilChanged в рамках Angular.
  4. StackBlitz – Angular Debounce Searchинтерактивный пример, где можно пощупать debounce в Angular.
  5. Medium – реализация debounce в Angular с помощью директивыв — статья о внедрении debounce в Angular через директиву.
  6. NgRx Docs – Debouncing Actions with RxJS — как реализовать debounce для действий в NgRx с помощью RxJS.
  7. YouTube – Angular Debounce Search Inputвидеоурок по созданию поиска с использованием debounce в Angular.