Добро пожаловать в этот обзор курса Pluralsight RxJS в Angular: реактивная разработка Деборы Курата.

Дебора - разработчик программного обеспечения, консультант и спикер конференции. Ее курсы включают: Angular: начало работы, Angular Routing и Основы объектно-ориентированного программирования на C #.

Этот курс длится чуть менее 4 часов. Если вы хотите быстро начать работу с RxJS, не тратя много времени, попробуйте книгу Скотта Аллена Начало работы с реактивным программированием с использованием RxJS, которая длится менее 2 часов. Тем не менее, вы узнаете больше из курса Деборы.

В курсе Angular Fundamentals есть модуль, который охватывает часть контента, который также представлен в этом курсе. Этот модуль называется общение с сервером с помощью http observables и rx. Я многому научился из этого, но теперь решил погрузиться глубже.

Введение

Дебора объясняет цели этого курса:

  • Добавьте ясности
  • Изучите декларативные и реактивные шаблоны
  • Улучшите управление состоянием с помощью этих шаблонов
  • Объединяйте потоки RxJS для управления данными из нескольких источников
  • Минимизируйте подписки для более чистого кода
  • Улучшение производительности пользовательского интерфейса

Что такое RxJS?

RxJS означает реактивные расширения для JavaScript. Первоначально он был разработан Microsoft как Rx.NET. Сейчас есть реализации на многих разных языках, включая JavaScript.

Официальная документация предоставляет обзор, в котором говорится:

RxJS - это библиотека для создания асинхронных программ, основанных на событиях, с использованием наблюдаемых последовательностей. Думайте о RxJS как о «Lodash для мероприятий ».

Другие подходы к работе с асинхронным JavaScript:

  • Обратные вызовы
  • Обещания
  • асинхронный / ожидание

Дебора описывает особенности и преимущества RxJS. К ним относятся:

  • Один метод, чтобы управлять ими всеми
  • Композиционный
  • Бдительный
  • Ленивый
  • Обрабатывает ошибки
  • Отменяемый

Мы используем RxJS для включения реактивной разработки

Что такое реактивная разработка?

реактивное программирование - это декларативная« парадигма программирования , связанная с потоками данных и распространением изменений».

Некоторые свойства реактивного развития:

  • Быстро реагировать на действия пользователя
  • Устойчивый к сбоям
  • Реагирует на изменения состояния

Предпосылки

Чтобы получить максимальную отдачу от курса, вам необходимо понимать основы Angular, в том числе:

  • Компоненты
  • Шаблоны
  • Услуги
  • Наблюдаемые / HttpClient

Если вы новичок в Angular, попробуйте курс Деборы Angular: Начало работы.

Код, сопровождающий этот курс, находится на GitHub здесь.

На этом мы завершаем введение в этот курс. Полный курс включает следующие модули. Загляните сюда позже, чтобы узнать об этом подробнее.

Термины и синтаксис RxJS

Во введении Дебора сравнивает наблюдаемые потоки с яблоками на конвейерной ленте.

Наблюдатель / подписчик

У Observer есть три основных метода, каждый из которых представляет собой уведомления:

  • next () - отправляет значение, такое как Число, Строка, Объект и т. д.
  • error () - отправляет ошибку или исключение JavaScript.
  • complete () - не отправляет значение

Для получения дополнительной информации см. Выполнение наблюдаемых.

Дебора дает несколько разных определений того, что такое наблюдатель. Самый простой - это то, что наблюдает за потоком и отвечает на его уведомления.

подписчик - это наблюдатель с дополнительной возможностью отписаться от Observable.

Наблюдаемый поток

Здесь есть несколько взаимозаменяемых терминов:

  • Наблюдаемая последовательность
  • Наблюдаемое
  • Поток

Наблюдаемые могут быть синхронными или асинхронными и могут выдавать конечное или бесконечное количество значений! Примером бесконечного количества значений является счетчик каждой секунды для таймера.

Запускаем стрим, подписавшись на него.

Есть несколько способов остановить поток:

  • Вызывая полный метод
  • Используйте завершающий оператор (например, of, from, take)
  • Выдает ошибку (это не вызывает завершение)
  • Отказ от подписки (это не называется полным)

Функции создания

из и из являются функциями создания.

Разница между of и from заключается в том, что в случае массива элементов of возвращает одно значение, которое является массивом, а from возвращает каждое из значений отдельных элементов.

Функции создания: демонстрация

Дебора демонстрирует операторы of и from с помощью stackblitz.

Чтобы импортировать только эти операторы, мы:

import { of, from } from ‘rxjs’;

Добавив эту строку в метод ngOnInit

of(2,4,6,8).subscribe(console.log);

Мы видим, что каждое из значений элемента выводится на консоль.

Аргумент from - это массив:

from([2,4,6,8]).subscribe(console.log);

Затем Дебора завершает этот модуль резюме и контрольным списком.

Операторы RxJS

Обзор оператора

Дебора представляет метод трубы наблюдаемого. Он действует как конвейер, потому что в него можно включить несколько других операций.

Все операторы RxJS описаны в официальном справочном API. Есть более 100 операторов, и вряд ли вы когда-нибудь воспользуетесь ими всеми. Мы рассмотрим некоторые из наиболее распространенных операторов в этом модуле, а другие рассмотрим позже в этом курсе.

Документация включает множество мраморных диаграмм, на которых элементы потока представлены в виде движущихся шариков. Верхняя строка представляет исходную (или входную) наблюдаемую, а нижняя строка представляет собой выходную наблюдаемую. Например, это показывает, что значения элементов умножаются на 10:

Также полезно Дерево решений оператора. Мы можем использовать это, чтобы помочь найти лучшего оператора для удовлетворения наших потребностей.

карта

Карта трансформирует каждый испускаемый элемент так, как вы хотите, чтобы он трансформировался. Это очень часто используется и полезно всякий раз, когда вам нужно изменить каждый элемент в потоке.

Карта - это оператор преобразования.

Кран

Оператор тап переходит в поток, не изменяя его. Это полезно для безопасной проверки значений в нашем потоке, например, при отладке.

Tap является оператором коммунальных услуг.

Возьмите

Оператор take выдает указанное количество элементов. Например, take (2) испускает первые два элемента в потоке.

Также есть оператор takeLast, который работает с конца потока, а не с начала.

Take - это оператор фильтрации.

Демо

Дебора показывает карту, нажмите и возьмите операторов с помощью StackBlitz. Она говорит, что в следующем модуле мы будем использовать их в других сценариях реального мира.

Внутреннее устройство оператора

Дебора показывает упрощенный вид кода оператора карты и объясняет, как он работает. Это менее сложно, чем вы думаете.

Затем Дебора завершает этот модуль резюме и контрольным списком.

Становится реактивным

Реактивность означает программирование с упором на асинхронные потоки данных. Дебора говорит, что это улучшает производительность, обрабатывает состояние, реагирует на действия пользователя и упрощает наш код!

Образец заявки

Образец приложения находится на GitHub здесь.

Это снова старое доброе приложение ACME Product Management. Возможно, вы видели это из таких курсов, как Angular: Начало работы, Реактивные формы Angular, Угловая маршрутизация и NgRx: Начало работы.

Мы начинаем приложение с кода процедурного стиля, и мы изменим его, чтобы он стал реактивным.

Работа с асинхронным конвейером

Использование асинхронного конвейера не требует каких-либо изменений в коде нашей службы.

Нам просто нужно обновить наш компонент и код шаблона.

В нашем компоненте списка продуктов мы начинаем с метода ngOnInit, который подписывается на метод getProducts в нашей productService.

вместо использования массива Product мы определяем Observable массива Product, а в ngOnInit мы устанавливаем для нашего наблюдаемого свойства this.productService.getProducts ();

Поскольку асинхронный конвейер обрабатывает нашу подписку, нам больше не нужно вызывать метод подписки в ngOnInit.

В шаблоне, где у нас было

<div *ngIf="products">

Мы меняем это на

<div *ngIf="products$ | async as products">

Здесь продукты - это массив продуктов, выпущенных из наблюдаемых продуктов $. По соглашению знак $ в конце имени указывает, что это наблюдаемая. Мы должны импортировать Observable из rxjs в наш компонент, но опция быстрого исправления VS Code упрощает это.

Дебора демонстрирует, сколько кода мы можем удалить с помощью этой техники: нам больше не нужен метод ngOnDestroy или реализация OnDestroy в компоненте списка продуктов.

Обработка ошибок

Мы удалили нашу обработку ошибок в предыдущем ролике.

Две основные стратегии обработки ошибок с помощью наблюдаемых:

  • Поймай и замени
  • Поймай и перебрось

Дебора вводит оператор catchError. Это оператор обработки ошибок.

Стратегия "поймать и заменить" эффективно заменяет наблюдаемые данные другими определенными данными в случае ошибки.

Перехват и повторный выброс дают нам возможность зарегистрировать ошибку или выполнить с ней какую-либо другую обработку, а затем повторно выбросить ее с помощью оператора throwError.

Если он всплывает полностью, пользователь получает уведомление об ошибке.

Оператор throwError - это функция создания.

Дебора также представляет EMPTY. Это константа, представляющая пустую наблюдаемую. Затем следует демонстрация этих стратегий обработки ошибок.

Преимущества асинхронного канала

  • Нет необходимости подписываться
  • Не нужно отказываться от подписки
  • Возможность повышения производительности за счет изменения обнаружения изменений

Стратегии обнаружения изменений

По умолчанию - каждый компонент проверяется при обнаружении любого изменения.

OnPush - повышает производительность за счет минимизации циклов обнаружения изменений

Мы можем установить стратегию обнаружения изменений в декораторе компонентов следующим образом:

changeDetection: ChangeDetectionStrategy.OnPush

Влияние на производительность становится заметным только в том случае, если мы работаем на экране с множеством различных элементов пользовательского интерфейса.

В стратегии обнаружения изменений OnPush нам нужно указать Angular, когда следует выполнять обнаружение изменений.

Декларативный шаблон для поиска данных

Преимущества декларативного подхода

  • Использует возможности операторов RxJS
  • Может эффективно комбинировать наблюдаемые потоки
  • Легко делитесь наблюдаемыми
  • Быстро реагировать на действия пользователя

Отображение возвращенных данных

Вот некоторые примеры использования простого сопоставления возвращаемых данных:

  • изменение значения (например, добавление налога с продаж)
  • преобразование значения (например, из истинного в ложное)
  • изменение имени поля
  • добавить вычисляемое поле

Этот модуль охватывает некоторые более сложные случаи.

Отображение ответа Http

Эти следующие несколько клипов очень важны!

Он показывает, как сопоставить HTTP-ответ, передать его по конвейеру и применить к нему оператор сопоставления.

Иногда ответ на HTTP-запрос содержит массив элементов. Служба HttpClient автоматически сопоставляет ответ с определенной формой, например Product [], если ответ является массивом элементов Product.

Дебора говорит, что наш подход должен быть следующим:

  1. Сопоставьте испускаемый массив
  2. Сопоставьте каждый элемент в массиве
  3. Преобразуйте каждый элемент

После пары следующих роликов мы подходим к решению. Это умножает цену каждого элемента на 1,5:

product$= this.http.get<Product[]>(this.productUrl)
.pipe(
 map(products => 
 products.map(products => ({
...product,
price: product.price * 1.5}) as Product)
 ),

Обратите внимание, что мы используем оператор распространения, а также предложение as для ввода результата в Product.

product $ имеет тип Observable ‹Product []›

Это не так сложно, как может показаться на первый взгляд. Если вы посмотрите отрывок и послушаете объяснение Деборы, весь процесс станет понятным.

Следующие модули охватывают более сложные сценарии.

Объединение потоков

Мы можем объединить наблюдаемые потоки, чтобы:

  • Сопоставьте идентификатор со строкой
  • Работа с несколькими источниками данных
  • Реагировать на действия
  • Упростите наш код шаблона

Этот модуль охватывает следующие операторы создания RxJS:

Функция создания RxJS: combLatest

Это объединяет несколько Observable для создания Observable, значения которого вычисляются из последних значений каждого из его входных Observable.

Это намного легче понять на примере - взгляните на мраморную диаграмму, которая показывает пример объединения двух потоков.

combLatest ничего не испускает, пока все потоки не испускают хотя бы одно значение.

Дебора говорит, что этот оператор полезен для переоценки состояния при возникновении действия. Она приводит пример фильтрации списка после действия выбора фильтра.

Функция создания RxJS: forkJoin

Официальное определение RxJS:

Принимает Array из« ObservableInput или словарь Object из ObservableInput и возвращает Observable, который испускает либо массив значений в том же порядке, что и переданный массив, либо словарь значений в той же форме, что и переданный словарь».

Более простое определение Деборы - «создать Observable, значение которого определяется с использованием последнего значения из каждого входного Observable».

Я предпочитаю определение Деборы, но оно по-прежнему многословно и сложно для понимания. Посмотрите на мраморную диаграмму, чтобы лучше понять ее функцию.

Дебора рекомендует использовать этот оператор, чтобы дождаться обработки любых результатов, пока не будут завершены все потоки. Например, когда вам нужно выполнить несколько HTTP-запросов и вы не хотите обрабатывать какие-либо результаты, пока не будут завершены все потоки.

Оператор RxJS: withLatestFrom

«Каждый раз, когда исходный Observable выдает значение, он вычисляет формулу, используя это значение плюс последние значения из других входных Observable, а затем выдает результат этой формулы».

Это в чем-то похоже на combLatest, но с той разницей, что существует единственный исходный поток, и ничего не происходит, кроме случаев, когда этот исходный поток передает значение.

Обратите внимание на мраморную диаграмму. На этой диаграмме верхняя строка - это исходный поток.

Дебора рекомендует использовать этот оператор, чтобы реагировать на изменения только в одном потоке или регулировать вывод других потоков.

Объединение потоков для сопоставления идентификатора со строкой

Мы снова вернемся к приложению ACME Product App и посмотрим, как перейти от числа, представляющего категорию продукта, к имени категории.

Это делается путем добавления нового свойства в интерфейс продукта для хранения названий категорий.

Мы используем http.get для получения данных Product и ProductCategory в виде наблюдаемых потоков. Затем объединяем их с помощью combLatest. Мы сопоставляем идентификатор со строкой с помощью метода find массива категорий.

Объединение потоков для сопоставления идентификатора со строкой: демонстрация

Дебора знакомит с необходимыми изменениями в коде Visual Studio.

Это включает в себя внедрение ProductCategoryService в нашу службу продукта. Мы используем операторы RxJS: combLatest, pipe, map и find.

В шаблоне мы меняем с product.categoryId на product.category, чтобы отображать категорию в виде строки.

Резюме и контрольные списки

Это резюмирует то, что мы узнали в этом модуле.

Реагируя на действия

"Введение"

В этом модуле мы будем изучать фильтр, startWith, Subject и BehaviorSubject.

Фильтрация потока

Фильтрация потока: демонстрация

Фильтрация потока: демонстрация II

Поток данных против потока действий

Тема и поведение

Реагируя на действия

Начиная с начального значения

Резюме и контрольные списки

Чтобы узнать об этом, посмотрите курс Pluralsight.

Реагирование на действия: примеры

Чтобы узнать об этом, посмотрите курс Pluralsight.

Кэширование наблюдаемых

Чтобы узнать об этом, посмотрите курс Pluralsight.

Операторы отображения высшего порядка

Чтобы узнать об этом, посмотрите курс Pluralsight.

Объединение всех потоков

Чтобы узнать об этом, посмотрите курс Pluralsight.

Заключительные слова

Чтобы узнать об этом, посмотрите курс Pluralsight.