Что привлекает в Ангуляре экспертов и удручает начинающих? Одно и тоже, RxJS.
![](https://webcf.waybackmachine.org/web/20221118015859/https://habrastorage.org/getpro/habr/upload_files/cba/13f/a0d/cba13fa0ddebb05e18e185681c9bb2c4.png)
Почему же это так сложно для начинающих? Одна из причин - есть огромное количество операторов, которые нужно просто знать, и без поиска понимать в чем разница между concatMap, switchMap и mergeMap. Почему же это так нравится тем, кто это уже изучил? Потому что вы начинаете понимать все могуществао RxJS, когда парой операторов вы можете сделать то, что в императивном коде писали бы полдня на двух страницах. Ведь это так приятно, ощущать себя богом, когда код просто отскакивает от ваших пальцев, а вы радостно рассказываете коллегам как вы классно и главное просто решили задачу.
Вместе с тем каждый помнит, что вызывать множественные subscribe плохо (как и вообще подписываться), вызывать сайд эффекты из tap (хотя конечно все так делают). А что же чаще всего забывают с RxJS? Ошибки. Какие ошибки? Лично я выделяю всего два типа ожидаемые и неожиданные.
Неожиданные ошибки - это те ошибки, которые возникают в результате плохого кода либо неожиданного JSON-ответа сервера - деление на ноль, обращение к null-объекту, некорректный парсинг JSON. Можно привести много примеров, главное то, что это полноценные ошибки, которые требуют изменений в вашем коде.
Ожидаемые ошибки - это ошибки, которые мы можем предусмотреть в работе приложения, самый простой пример - это упавший сервер с данными. Тут мы как программисты в своем коде ничего не правим, а обычно идем ругаться в другую команду.
Такие типы ошибок, я считаю, надо разделять и в последствиях - в случае первых красиво падать, в случае вторых - уметь с ними работать и показывать нашим пользователям что-то, из чего можно сделать красивый скриншот “виноваты они а не мы”. Как это сделать? Используя такое представление данных, которое само по себе покажет вам, что в нем могут быть как данные, так и ошибка. Встречайте,
![](https://webcf.waybackmachine.org/web/20221118015859/https://habrastorage.org/getpro/habr/upload_files/52d/5d1/5f9/52d5d15f9a7839e51fe2cf26f17de10d.png)
В общем случае это union тип, слева - ошибка, справа - правильные данные.
Впрочем, самописный тип я предлагаю не использовать, а взять готовый. Многие берут тип из библиотеки fp-ts, я же предлагаю взять более легковесный и понятный @sweet-monads/either.
![](https://webcf.waybackmachine.org/web/20221118015859/https://habrastorage.org/getpro/habr/upload_files/4b3/00f/b9a/4b300fb9abe4a8500e81a93fb1faa184.png)
Давайте создадим простое Ангуляр-приложение, которое будет грузить данные пользователя github, а потом (не)красиво падать при попытке загрузки несуществующего по нажатию кнопок.
![](https://webcf.waybackmachine.org/web/20221118015859/https://habrastorage.org/getpro/habr/upload_files/d4b/3ee/a55/d4b3eea554e820524604f546f4f2baf0.png)
Код, соответственно, выглядит вот так
![](https://webcf.waybackmachine.org/web/20221118015859/https://habrastorage.org/getpro/habr/upload_files/4ce/5a6/154/4ce5a6154d6a00bfec5adc66f5637ddc.png)
Это довольно простое приложение, падающее при попытке сделать что-то, о чем мы не подумали (в данном случае - загрузить несуществующего пользователя). Печально, но визуально это будет выглядеть в лучшем случае как неработающая кнопка, в худшем - все, что было основано на таком коде, также упадет.
Попыток решения ошибок способами RxJS много, предлагаю изучить в прекрасной статье RxJs Error Handling: Complete Practical Guide
В Ангуляре я чаще всего видел решение через определение в модели компонента отдельных полей data и error.
![](https://webcf.waybackmachine.org/web/20221118015859/https://habrastorage.org/getpro/habr/upload_files/99d/be1/da8/99dbe1da863bb9ce5b9a8b155f61bbdf.png)
Почему это (а также другие способы решения) плохо предлагаю посмотреть в прекрасном ролике от Артём Кобзаря и Дмитрия Махнёва (не|ну)жная монада Either на практике и в теории
Ну а в действительности мы об этом просто забываем до тех пор, пока не упадет, и решаем такие проблемы точечно. Я же предлагаю изначально считать ошибки полноценными жителями нашего города и никогда не верить бэкенду, даже если мы счастливые обладатели звания FullStack Developer.
Для начала давайте напишем простой RxJS оператор, который будет автоматически ловить ошибки и преобразовывать их в структуру ошибки. Для простоты давайте сохранять только текст ошибки.
![](https://webcf.waybackmachine.org/web/20221118015859/https://habrastorage.org/getpro/habr/upload_files/f21/283/272/f21283272911c084f52bfd4cf6264039.png)
В чём прелесть такого оператора как отдельной единицы в в приложении - то что мы можем его применять точечно, в отдельных местах приложения, а не мигрировать целиком.
Код с использованием этого оператора будет выглядеть вот так
![](https://webcf.waybackmachine.org/web/20221118015859/https://habrastorage.org/getpro/habr/upload_files/5a0/256/fd3/5a0256fd364ddee76019004fcc9bcc15.png)
Показывать же данные в html лучше через создание специальных директив и компонент-врапперов (также оно в альфа-версии доступно в npm как пакет) Приводить их тут не буду, предлагаю изучить сразу обновленный пример, включая код, по этой ссылке.
![](https://webcf.waybackmachine.org/web/20221118015859/https://habrastorage.org/getpro/habr/upload_files/f72/248/a48/f72248a484bc77232dba17c3a8cbb358.png)
Основные изменения - появление компонента Either и использование правых данных через структурную директиву ifRight.
Теперь при падении мы покажем текст ошибки, а в случае загруженных данных будем работать с ними.
![](https://webcf.waybackmachine.org/web/20221118015859/https://habrastorage.org/getpro/habr/upload_files/ffb/d4e/c79/ffbd4ec79ddb311ef950b19718661964.png)
Заключение
Как видите, здесь мы уверены что ошибка будет обработана более то в будущем если нам понадобится мы всегда сможем например залогировать как с помощью операторов mapEither, switchMapEither (есть в примере)