Pull to refresh

Ошибки, RxJS & Angular

Reading time3 min
Views3.3K

Что привлекает в Ангуляре экспертов и удручает начинающих? Одно и тоже, RxJS.

Почему же это так сложно для начинающих? Одна из причин - есть огромное количество операторов, которые нужно просто знать, и без поиска понимать в чем разница между concatMap, switchMap и mergeMap. Почему же это так нравится тем, кто это уже изучил? Потому что вы начинаете понимать все могуществао RxJS, когда парой операторов вы можете сделать то, что в императивном коде писали бы полдня на двух страницах. Ведь это так приятно, ощущать себя богом, когда код просто отскакивает от ваших пальцев, а вы радостно рассказываете коллегам как вы классно и главное просто решили задачу.

Вместе с тем каждый помнит, что вызывать множественные subscribe плохо (как и вообще подписываться), вызывать сайд эффекты из tap (хотя конечно все так делают). А что же чаще всего забывают с RxJS? Ошибки. Какие ошибки? Лично я выделяю всего два типа ожидаемые и неожиданные.

Неожиданные ошибки - это те ошибки, которые возникают в результате плохого кода либо неожиданного JSON-ответа сервера - деление на ноль, обращение к null-объекту, некорректный парсинг JSON. Можно привести много примеров, главное то, что это полноценные ошибки, которые требуют изменений в вашем коде.

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

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

Давайте создадим простое Ангуляр-приложение, которое будет грузить данные пользователя github, а потом (не)красиво но ожидаемо падать при попытке загрузки несуществующего.

StackBlitz Demo

Код, соответственно, выглядит вот так:

Это довольно простое приложение, падающее при попытке сделать что-то, о чем мы не подумали (в данном случае - загрузить несуществующего пользователя). Печально, но визуально это будет выглядеть в лучшем случае как неработающая кнопка, в худшем - все, что было основано на таком коде, также упадет.

Попыток решения ошибок способами RxJS много, предлагаю изучить в прекрасной статье RxJs Error Handling: Complete Practical Guide

В Ангуляре я чаще всего видел решение через определение в модели компонента отдельных полей data, error и isLoading.

В нашем случае темплейт разрастается на каждую ветку

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

StackBlitz Demo

Почему это (а также другие способы решения) плохо предлагаю посмотреть еще и в оригинальном ролике от Артём Кобзаря и Дмитрия Махнёва (не|ну)жная монада Either на практике и в теории. В действительности мы о таких ожидаемых ошибках просто забываем до тех пор, пока не упадет, и решаем такие проблемы точечно. Я же предлагаю изначально считать ошибки полноценными жителями нашего города и никогда не верить бэкенду, даже если мы счастливые обладатели звания FullStack Developer.

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

В общем случае это union тип, слева - ошибка, справа - правильные данные.

Впрочем, самописный тип я предлагаю не использовать, а взять готовый. Многие берут тип из библиотеки fp-ts, я же предлагаю взять более легковесный и понятный @sweet-monads/either.

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

В чём прелесть такого оператора как отдельной единицы в в приложении - то что мы можем его применять точечно, в отдельных местах приложения, а не мигрировать целиком. Также такой оператор отделяет ожидаемые ошибки от неожиданных.

Код с использованием этого оператора будет выглядеть вот так

Показывать же данные в html лучше через создание специальных директив и компонент-врапперов (также оно в альфа-версии доступно в npm как пакет) Приводить их тут не буду, предлагаю изучить сразу обновленный пример, включая код, по этой ссылке.

 Основные изменения - появление компонента Either и использование правых данных через структурную директиву ifRight.

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

Заключение

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

Tags:
Hubs:
Total votes 3: ↑3 and ↓0+3
Comments26

Articles