Введение
Observables — это мощный и универсальный инструмент для обработки асинхронных потоков данных в JavaScript. Они похожи на обещания, но с несколькими ключевыми отличиями, которые делают их более мощными и гибкими.
Самый простой способ представить наблюдаемую — это поток данных, который может быть испущен с течением времени. Наблюдаемый объект может выдавать любое количество значений, а также сигнализировать о завершении или сбое потока.
Одним из ключевых преимуществ использования наблюдаемых объектов является то, что они позволяют легко подписаться и отказаться от подписки на поток данных. С промисом вы можете получить разрешенное значение только один раз, тогда как с наблюдаемым вы можете подписаться на него и получать обновления по мере их поступления. Это делает наблюдаемые объекты идеальными для обработки данных в реальном времени, таких как пользовательский ввод или ответы сервера.
Еще одним преимуществом observables является возможность использования операторов для манипулирования потоком данных и работы с ним. Операторы — это функции, которые могут быть объединены в цепочку для преобразования, фильтрации или объединения наблюдаемых. Это обеспечивает высокую степень гибкости и контроля над потоком данных.
В Angular observables широко используются, а библиотека RxJS предоставляет широкий набор операторов для работы с observables. Они используются для обработки асинхронных данных и событий, таких как пользовательский ввод, HTTP-запросы и ответы и многое другое. Они также играют ключевую роль в обнаружении изменений, позволяя Angular эффективно обновлять представление при изменении базовых данных.
Кроме того, наблюдаемые объекты можно использовать для связи между компонентами, службами и другими частями приложения. Это позволяет использовать более реактивный и эффективный способ обработки данных и событий, в отличие от традиционных методов, таких как обратные вызовы или события.
Наблюдаемые объекты RxJS
Работа с наблюдаемыми и RxJS может значительно улучшить функциональность и производительность вашего приложения. Чтобы начать работать с наблюдаемыми в приложении, вам сначала нужно импортировать библиотеку RxJS и все необходимые модули. Вы можете сделать это, добавив следующую строку:
import { Observable } from 'rxjs';
Далее вам нужно создать наблюдаемый объект и подписаться на него. Например, вы можете создать наблюдаемую, которая выдает строку каждую секунду:
let myObservable = new Observable(observer => { setInterval(() => { observer.next("Hello World!"); }, 1000); });
Затем вы можете подписаться на наблюдаемые и получать обновления:
myObservable.subscribe(val => console.log(val));
Другой способ подписаться на наблюдаемое в Angular — использовать асинхронный канал в вашем шаблоне. Это позволяет вам привязывать наблюдаемые непосредственно к вашему шаблону, устраняя необходимость вручную подписываться и отписываться в коде вашего компонента.
<ng-container *ngIf="myObservable | async as myValue"> {{myValue}} </ng-container>
После того, как вы настроили наблюдаемые объекты, вы можете начать работать с ними, используя различные операторы. Например, вы можете использовать оператор map
для преобразования данных, испускаемых наблюдаемым объектом:
myObservable.pipe( map(val => val.toUpperCase()) ).subscribe(val => console.log(val));
В службах и компонентах Angular вы можете использовать наблюдаемые объекты для обработки асинхронных данных и событий. Например, вы можете создать наблюдаемую в службе, которая отправляет обновления с сервера, и подписаться на нее в компоненте для отображения данных в вашем шаблоне.
Работа с наблюдаемыми RxJS в Angular
Создание наблюдаемых из различных источников
Существует несколько способов создания наблюдаемых объектов в JavaScript, и многие из них можно использовать в приложениях Angular. Некоторые распространенные источники для создания наблюдаемых включают:
- Пользовательский ввод: вы можете создать наблюдаемое из событий пользовательского ввода, таких как нажатия клавиш или клики. Например, вы можете создать наблюдаемую, которая выдает значение поля ввода каждый раз, когда пользователь вводит его:
let input = document.getElementById('myInput'); let inputObservable = fromEvent(input, 'keyup').pipe( map(event => event.target.value) );
- Таймеры: вы можете создавать наблюдаемые, которые выдают значения через заданный интервал или после задержки. Например, вы можете создать наблюдаемую, которая выдает текущее время каждую секунду:
let timerObservable = interval(1000).pipe(map(() => new Date()));
- HTTP-запросы: вы можете создавать наблюдаемые объекты, которые выдают ответ на HTTP-запрос. Angular предоставляет модуль
HttpClient
для выполнения HTTP-запросов, который по умолчанию возвращает наблюдаемые данные. Например, вы можете создать наблюдаемую, которая выдает ответ на запрос GET на определенный URL-адрес:
let httpObservable = this.http.get<MyType>('http://example.com/data').pipe( tap(value => console.log(value)) );
- WebSockets: вы можете создавать наблюдаемые объекты, которые отправляют сообщения, полученные через соединение WebSocket. Вы можете использовать класс RxJS
WebSocketSubject
для создания наблюдаемого объекта, который отправляет сообщения, полученные через соединение WebSocket.
let wsObservable = new WebSocketSubject<MyType>('ws://example.com/ws');
- Промисы: вы можете создавать наблюдаемые объекты из промисов, используя оператор
from
илиfromPromise
.
let promise = fetch('http://example.com/data').then(response => response.json()); let promiseObservable = from(promise);
Это всего лишь несколько примеров множества способов создания наблюдаемых объектов в JavaScript. После создания наблюдаемого объекта вы можете использовать операторы для преобразования, фильтрации или объединения потока данных, прежде чем подписываться на него. Это обеспечивает высокую степень гибкости и контроля над потоком данных, что делает observables мощным инструментом для обработки асинхронных данных и событий в приложениях Angular.
Преобразование наблюдаемых с помощью операторов
Операторы — это функции, которые можно использовать для манипулирования и преобразования данных, испускаемых наблюдаемым объектом. Некоторые общие операторы для преобразования наблюдаемых включают в себя:
map
: оператор map
используется для преобразования данных, испускаемых наблюдаемой. Он принимает функцию обратного вызова в качестве аргумента, который применяется к каждому значению, испускаемому наблюдаемым, и возвращает новый наблюдаемый, который испускает преобразованные значения. Например, допустим, у вас есть наблюдаемый объект, который генерирует массив пользовательских объектов, и вы хотите преобразовать его в наблюдаемый объект, который генерирует массив полных имен пользователей. Для этого вы можете использовать оператор map
.
let userObservable = of([ { firstName: 'John', lastName: 'Doe' }, { firstName: 'Jane', lastName: 'Doe' }] ); let fullNameObservable = userObservable.pipe( map(users => users.map(user => `${user.firstName} ${user.lastName}`)) );
filter
: оператор filter
используется для фильтрации определенных значений, испускаемых наблюдаемым. Он принимает функцию обратного вызова в качестве аргумента, который применяется к каждому значению, выдаваемому наблюдаемым, и выдает только те значения, которые проходят тест. Например, вы можете использовать оператор filter
для фильтрации нечетных чисел из наблюдаемой, которая выдает последовательность чисел:
let myObservable = of(1, 2, 3, 4, 5); let filteredObservable = myObservable.pipe( filter(val => val % 2 === 0) );
concatMap
: оператор concatMap
используется для сопоставления каждого значения с внутренним наблюдаемым и объединения результатов. Он похож на оператор flatMap
, но сохраняет порядок внутренних наблюдаемых. Например, предположим, что у вас есть наблюдаемый объект, который генерирует массив идентификаторов пользователей, и вы хотите сделать HTTP-запрос для каждого идентификатора пользователя, чтобы получить сведения о пользователе. Для этого вы можете использовать оператор concatMap
.
let userIdObservable = of([1, 2, 3, 4]); let userDetailObservable = userIdObservable.pipe( concatMap(userIds => userIds.map(id => this.http.get(`/api/users/${id}`))) );
mergeMap
: оператор mergeMap
используется для сопоставления каждого значения с внутренней наблюдаемой величиной и объединения результатов. Он похож на оператор flatMap
, но не поддерживает порядок внутренних наблюдаемых. Например, предположим, что у вас есть наблюдаемый объект, который генерирует поток условий поиска, и вы хотите сделать HTTP-запрос для каждого условия поиска и объединить результаты.
let searchObservable = of('Angular', 'React', 'Vue'); let searchResultsObservable = searchObservable.pipe( mergeMap(searchTerm => this.http.get(`/api/search?q=${searchTerm}`)) );
switchMap
: оператор switchMap
используется для сопоставления каждого значения с внутренним наблюдаемым и выдает только самое последнее наблюдаемое значение. Он откажется от предыдущих внутренних наблюдаемых и переключится на последние внутренние наблюдаемые. Например, предположим, что у вас есть наблюдаемый объект, который выдает поток поисковых запросов, и вы хотите сделать HTTP-запрос для каждого поискового запроса, но выдать только результаты самого последнего поискового запроса. Для этого вы можете использовать оператор switchMap
.
let searchObservable = fromEvent(searchInput, 'keyup').pipe( map((event: any) => event.target.value), switchMap(searchTerm => this.http.get(`/api/search?q=${searchTerm}`)) );
Это всего лишь несколько примеров из множества операторов, доступных для преобразования наблюдаемых в RxJS. Объединяя операторы вместе, вы можете создавать сложные и мощные потоки данных, которые можно использовать для обработки асинхронных данных и событий в приложениях Angular.
Объединение наблюдаемых с помощью операторов
В приложениях Angular существует несколько способов объединения наблюдаемых с помощью операторов. Вот некоторые распространенные примеры:
- Объединение значений нескольких входных данных формы: вы можете создавать наблюдаемые объекты из событий valueChanges нескольких элементов управления формы, а затем использовать оператор
combineLatest
для объединения значений в один наблюдаемый объект, который создает объект с последними значениями всех элементов управления формы.
let firstNameControl = new FormControl(); let lastNameControl = new FormControl(); let combinedObs = combineLatest( firstNameControl.valueChanges, lastNameControl.valueChanges ).pipe(map(([firstName, lastName]) => ({firstName, lastName})));
- Объединение результатов нескольких HTTP-запросов: вы можете использовать оператор
forkJoin
для объединения результатов нескольких HTTP-запросов в один наблюдаемый объект.
let obs1 = this.http.get('/api/data1'); let obs2 = this.http.get('/api/data2'); let combinedObs = forkJoin({data1: obs1, data2: obs2});
- Объединение нескольких наблюдаемых действий пользователя: вы можете создавать наблюдаемые из различных действий пользователя, таких как клики, нажатия клавиш и т. д., а затем использовать оператор
merge
, чтобы объединить их в один наблюдаемый.
let clickObservable = fromEvent(document, 'click'); let keyObservable = fromEvent(document, 'keyup'); let combinedObs = merge(clickObservable, keyObservable);
Это всего лишь несколько примеров множества способов объединения наблюдаемых в приложениях Angular. Используя такие операторы, как merge
, combineLatest
, forkJoin
, вы можете создавать сложные и мощные потоки данных, которые можно использовать для обработки асинхронных данных и событий в приложениях Angular.
Обработка ошибок в наблюдаемых
Обработка ошибок в наблюдаемых объектах — важный аспект работы с асинхронными данными в приложениях Angular. Существует несколько способов обработки ошибок в наблюдаемых, в том числе:
- Использование оператора
catchError
: ОператорcatchError
используется для обработки ошибок, возникающих в наблюдаемом объекте. Он принимает функцию обратного вызова в качестве аргумента, который вызывается с ошибкой, и возвращает новый наблюдаемый объект, который выдает либо ошибку, либо резервное значение. Например, вы можете использовать операторcatchError
для обработки ошибок, возникающих во время HTTP-запроса:
import { catchError } from 'rxjs/operators'; let httpObservable = this.http.get('/api/data').pipe( catchError(error => { console.error(error); return of([]); }) );
- Использование оператора
retry
: операторretry
можно использовать для повторной попытки наблюдаемого при возникновении ошибки. Он принимает число в качестве аргумента, указывающего, сколько раз повторять наблюдаемое, прежде чем сдаться. Например, вы можете использовать операторretry
, чтобы несколько раз повторить HTTP-запрос, прежде чем сдаться:
import { retry } from 'rxjs/operators'; let httpObservable = this.http.get('/api/data').pipe( retry(3) );
- Использование оператора
retryWhen
: ОператорretryWhen
можно использовать для повторной попытки наблюдаемого при возникновении ошибки. Он принимает функцию, которая получает наблюдаемое количество ошибок и возвращает наблюдаемое значение, указывающее, когда следует повторить попытку. Это позволяет более точно контролировать, когда и как повторять наблюдаемое. Например, вы можете использовать операторretryWhen
для повторной попытки HTTP-запроса после определенной задержки:
import { retryWhen, delay } from 'rxjs/operators'; let httpObservable = this.http.get('/api/data').pipe( retryWhen(errors => errors.pipe(delay(3000))) );
- Использование оператора
take
: Операторtake
можно использовать для ограничения количества выбросов от наблюдаемой. В качестве аргумента он принимает число, указывающее максимальное количество выпусков, которое необходимо выполнить перед отменой подписки. Например, вы можете использовать операторtake
, чтобы ограничить количество повторных попыток:
import { take } from 'rxjs/operators'; let httpObservable = this.http.get('/api/data').pipe( retryWhen(errors => errors.pipe(delay(3000))), take(5) );
Это всего лишь несколько примеров множества способов обработки ошибок в наблюдаемых в приложениях Angular. Важно правильно обрабатывать ошибки, чтобы убедиться, что ваше приложение может восстанавливаться после них и продолжать работать правильно.
Отписка от наблюдаемых
В приложениях Angular важно отписаться от наблюдаемых, когда они больше не нужны, чтобы предотвратить утечку памяти и повысить производительность приложения. Есть несколько способов отписаться от наблюдаемых в Angular, в том числе:
- Использование оператора
takeUntil
: ОператорtakeUntil
можно использовать для отказа от подписки на наблюдаемое, когда другое наблюдаемое выдает значение. Например, вы можете использовать операторtakeUntil
, чтобы отписаться от HTTP-запроса при уничтожении компонента:
import { takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; @Component({ // ... }) export class MyComponent implements OnInit, OnDestroy { private ngUnsubscribe = new Subject(); ngOnInit() { this.http.get('/api/data').pipe( takeUntil(this.ngUnsubscribe) ).subscribe(data => { /* ... */ }); } ngOnDestroy() { this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); } }
- Использование канала
async
: каналasync
— это удобная функция, которую можно использовать для автоматической отмены подписки на наблюдаемый объект при уничтожении компонента. Он часто используется в формах, управляемых шаблонами. Например, вы можете использовать каналasync
, чтобы отписаться от наблюдаемого объекта, который выдает пользовательские данные:
@Component({ template: ` <div *ngIf="userData$ | async as userData"> {{ userData.name }} </div> `, // ... }) export class MyComponent implements OnInit { userData$: Observable<User>; ngOnInit() { this.userData$ = this.http.get('/api/users/1'); } }
- Использование оператора
take
: Операторtake
можно использовать для ограничения количества выбросов от наблюдаемого перед отменой подписки. Например, вы можете использовать операторtake
, чтобы отписаться от наблюдаемого после первой эмиссии:
import { take } from 'rxjs/operators'; let myObservable = interval(1000).pipe( take(1) );
Важно отметить, что отмена подписки на наблюдаемые особенно важна при работе с наблюдаемыми, которые создаются внутри компонента или директивы, поскольку обнаружение изменений и перехватчики жизненного цикла Angular не отписываются автоматически от наблюдаемых, что создает утечки памяти.
Заключение
В заключение, работа с наблюдаемыми и RxJS в приложениях Angular — это мощный способ обработки асинхронных данных. Наблюдаемые объекты предоставляют способ обработки потоков данных и могут использоваться как в службах, так и в компонентах для обработки данных из внешних источников и взаимодействия с пользователем. Понимая, как создавать наблюдаемые объекты из различных источников, преобразовывать наблюдаемые объекты с помощью операторов и обрабатывать ошибки, вы сможете легко создавать отзывчивые и надежные приложения Angular. Кроме того, важно помнить, что подписку на наблюдаемые объекты следует отменять, когда они больше не нужны, чтобы предотвратить утечку памяти и повысить производительность. Благодаря знаниям и примерам, представленным в этом сообщении в блоге, у вас должно быть четкое представление о том, как работать с наблюдаемыми и RxJS в приложениях Angular.
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .
Заинтересованы в масштабировании запуска вашего программного обеспечения? Ознакомьтесь с разделом Схема.