Встроенная функция debounce в Angular 2+: поиск решения
Пройдите тест, узнайте какой профессии подходите
Быстрый ответ
Для повышения эффективности приложений Angular, можно воспользоваться оператором RxJS debounceTime
. Он позволяет ограничить частоту событий ввода в FormControl
с помощью valueChanges
:
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 мс, после истечения которой возвращается последнее введённое значение.
Углубляемся в основы
Работа с API-запросами или данными пользователя бывает сложной: поток событий может замедлить работу приложения и увеличить нагрузку на систему. В этом случае на помощь придёт debounce, который задерживает обработку действия до истечения определенного периода бездействия. Особенно ценно это для фреймворка Angular и работы с формами.
Управление событиями вне Angular
Хотите повысить производительность? Пригодится ngZone.runOutsideAngular() — это позволит выполнять действия, минуя систему отслеживания изменений Angular, что ускорит работу вашего приложения. Вот как это можно сделать:
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()
:
import { ChangeDetectorRef } from '@angular/core';
constructor(private cdr: ChangeDetectorRef) {}
// В какой-то части вашего компонента...
this.cdr.detectChanges(); // Указываем Angular проверить изменения
Если требуется запустить обнаружение изменений для всего приложения, используйте ApplicationRef.tick()
. Однако, следует быть осторожным: чрезмерное использование может негативно сказаться на производительности.
Оборачиваем debounce в готовое решение
Чтобы обеспечить переиспользование, стоит подумать о создании директивы или сервиса, которые бы инкапсулировали логику работы debounce. Директива подойдёт для шаблонных форм или для прямого применения к HTML-элементам:
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 после уничтожения вашего компонента, чтобы избежать утечек памяти.
Визуализация
Вообразите переполненный вокзал (🚉), где поезда (🚆) — это функциональные вызовы, следующие один за другим. Нам нужен именно тот поезд, который прибудет после периода бездействия, а не первый попавшийся:
| Ситуация | Визуализация |
|----------------------|---------------------|
| Постоянные вызовы | 🚆🚆🚆🚆🚆🚆🚆 |
| Применение Debounce | 🚆🚆🚆🕒...🚆 |
Debounce в Angular — это своего рода табло расписания (📅), которое сигнализирует (⏰) только о последнем прибывшем поезде после паузы:
// В Angular это выглядит так:
searchInput.valueChanges.pipe(
debounceTime(300) // Подождем 300 мс
).subscribe(value => {
// Обрабатываем только 'поезд', который прибыл после паузы
});
Ключевые моменты:
debounceTime(300)
позволяет провести действие только после прошедших 300 мс молчания.- Это подобно диспетчеру на вокзале, контролирующему поток поездов, чтобы избегать чрезмерной нагрузки.
Дополнения и задачи
Использование debounce может быть полезным, но требует обдуманного применения. Если нужно гарантировать выполнение действия с определенной периодичностью, сочетайте debounce с throttling:
import { throttleTime } from 'rxjs/operators';
// Пример использования троттлинга
inputControl.valueChanges
.pipe(throttleTime(300))
.subscribe(throttledValue => {
// Здесть появляется троттлированное событие
});
Если вы столкнулись с множеством последовательных одинаковых значений, используйте distinctUntilChanged
. Этот оператор не пропускает подряд идущие одинаковые значения и хорошо сочетается с debounce:
inputControl.valueChanges
.pipe(debounceTime(300), distinctUntilChanged())
.subscribe(value => {
// Работаем только с уникальными и отложенными значениями
});
Владение механизмами контроля за изменениями, умение повышать производительность через ngZone и знание различных операторов RxJS превратят вас в настоящего мастера обработки данных в Angular.
Полезные материалы
- Angular – оператор RxJS debounceTime — Официальная документация Angular по оператору debounce.
- RxJS – debounceTime — подробная документация RxJS.
- Learn JavaScript, Angular, React, RxJS, TypeScript — данная ссылка поможет разобраться с RxJS debounceTime и
distinctUntilChanged
в рамках Angular. - StackBlitz – Angular Debounce Search — интерактивный пример, где можно пощупать debounce в Angular.
- Medium – реализация debounce в Angular с помощью директивыв — статья о внедрении debounce в Angular через директиву.
- NgRx Docs – Debouncing Actions with RxJS — как реализовать debounce для действий в NgRx с помощью RxJS.
- YouTube – Angular Debounce Search Input — видеоурок по созданию поиска с использованием debounce в Angular.