Как значительно улучшить fetch() с помощью шаблона декоратора

От автора: fetch() API позволяет выполнять сетевые запросы в веб-приложениях. Использование fetch() довольно простое: invoke fetch(‘/movies.json’) для запуска запроса. Когда запрос завершится, вы получите объект Response, из которого можете извлечь данные.

Вот простой пример того, как получить некоторые фильмы в формате JSON с URL /movies.json:

Как показано в приведенном выше фрагменте кода, вы должны вручную извлечь объект JSON из ответа: moviesJson = await response.json(). Сделать один раз — не проблема. Но если ваше приложение выполняет много запросов, извлечение всего, что использует объект JSON await response.json(), утомительно.

В результате заманчиво использовать стороннюю библиотеку, такую как axios, которая значительно упрощает обработку запросов. Рассмотрим такую же загрузку фильмов, используя axios:

moviesJson = await axios(‘/movies.json’) возвращает фактический ответ в формате JSON. Вам не нужно вручную извлекать JSON, как того требует fetch().

Но … использование вспомогательной библиотеки вроде axios порождает собственный набор проблем.

Во-первых, он увеличивает размер пакета веб-приложения. Во-вторых, приложение связано со сторонней библиотекой: вы получаете все преимущества этой библиотеки, но также получаете все ее ошибки.

Я применяю другой подход, в котором используется лучшее из обоих вариантов — использование шаблона декоратора для повышения простоты использования и гибкости fetch() API. Давайте посмотрим в следующих разделах, как это сделать.

Подготовка интерфейса

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

Применение декоратора для улучшения fetch() требует нескольких простых шагов. Первый шаг — объявить абстрактный интерфейс с именем Fetcher:

Fetcher интерфейс имеет только один метод, который принимает те же аргументы и возвращает тот же тип данных, что и обычный fetch(). Второй шаг — реализация базового класса:

BasicFetcher реализует Fetcher интерфейс. Его единственный метод run() вызывает обычную функцию fetch() . Все просто. Давайте воспользуемся базовым классом для получения списка фильмов:

Попробуйте демо

Затем вы можете использовать decoratedFetch(‘/movies.json’) для получения фильмов точно так же, как при использовании обычного fetch().

На этом этапе клас BasicFetcher не приносят пользы. Тем более что все усложняется из-за нового интерфейса и нового класса! Подождите немного… вы увидите огромные преимущества, когда декораторы будут задействованы в действии.

Декоратор экстрактора JSON

Рабочей лошадкой паттерна декоратора является класс декоратора. Класс декоратора должен соответствовать Fetcherи нтерфейсу, оборачивать экземпляр, а также вводить дополнительные функции в метод run().

Давайте реализуем декоратор, который извлекает данные JSON из объекта ответа:

Давайте подробнее разберемся, как устроен JsonFetcherDecorator. JsonFetcherDecorator реализует интерфейс Fetcher. JsonExtractorFetch имеет закрытое поле decorateе которое также соответствует Fetcher интерфейсу. Внутри метода run() происходит фактическая выборка данных this.decoratee.run(input, init).

Затем json = await response.json() извлекает данные JSON из ответа. Наконец, response.data = json присваивает объекту ответа извлеченные данные JSON. Теперь давайте скомпонуем BasicFetcher с помощью JsonFetcherDecorator декоратора и упростим использование fetch():

Попробуйте демо

Теперь вместо извлечения вручную данных JSON из ответа вы можете получить доступ к извлеченным данным из dataс войства объекта ответа.

Переместив экстрактор JSON в декоратор, теперь в любом месте, которое вы используете, const { data } = decoratedFetch(URL) вам не придется вручную извлекать объект JSON.

Декоратор тайм-аута запроса

fetch() API по умолчанию отключает запросы во время, указанное браузером. В Chrome тайм-аут сетевого запроса составляет 300 секунд, а в Firefox — 90 секунд.

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

Что замечательно в шаблоне декоратора, так это то, что вы можете расширить свою базовую реализацию любым количеством декораторов! Итак, давайте создадим декоратор тайм-аута для запросов на выборку:

TimeoutFetcherDecorator — декоратор, реализующий Fetcher интерфейс. Внутри run() метода контроллер прерывания используется для прерывания запроса, если он не был завершен в течение 8 секунд.

Теперь давайте запустим этот декоратор:

Попробуйте демо

В демо запрос /movies.json занимает более 8 секунд. decoratedFetch(‘/movies.json’), благодаря TimeoutFetcherDecorator, выдает ошибку тайм-аута.

Теперь базовый сборщик обернут в 2 декоратора: один извлекает объект JSON, а другой тайм-аут запроса составляет 8 секунд. Это значительно упрощает использование decoratedFetch(): при вызове decoratedFetch() декораторов логика работает за вас.

Заключение

fetch() API предоставляет базовые функции для выполнения запросов на выборку. Но вам нужно больше! Использование fetch() только заставляет вас вручную извлекать данные JSON из запроса, настраивать тайм-аут и многое другое.

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

Альтернативное решение — использовать декоратор поверх fetch(). Вы можете создавать декораторы, которые извлекают JSON из запроса, задерживают запрос и многое другое. Вы можете комбинировать, добавлять или удалять декораторы в любое время, не затрагивая код, который использует декорированную выборку.

Хотели бы вы использовать fetch() с наиболее распространенными декораторами? Я создал для вас gist! Не стесняйтесь использовать его в своем приложении или даже добавлять декораторы для своих нужд!

Автор: Dmitri Pavlutin

Источник: dmitripavlutin.com

Редакция: Команда webformyself.

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии запрещены.