Retry и обработка сетевых ошибок

Slim.js — это легковесная библиотека для создания компонентов и управления состоянием в приложениях на JavaScript. Одной из важных задач при работе с внешними API является обработка сетевых ошибок и повторные попытки запросов (retry). Slim.js предоставляет гибкие механизмы для интеграции retry-логики напрямую в компоненты.

Механизм Retry

Retry в контексте сетевых запросов означает автоматическое повторение запроса при возникновении ошибки. Основные параметры, влияющие на поведение retry:

  • Количество попыток — число повторных запросов до окончательной ошибки.
  • Интервал между попытками — время ожидания перед новой попыткой.
  • Стратегия экспоненциального увеличения задержки — постепенное увеличение интервала после каждой неудачной попытки.
  • Фильтр ошибок — определение, какие ошибки требуют повторной попытки (например, таймауты или сетевые ошибки, но не ошибки валидации).

Реализация retry через функции Slim.js

Slim.js использует реактивное состояние, что позволяет интегрировать retry в асинхронные действия компонента. Простейшая структура выглядит так:

import { Slim } from 'slim-js';

class FetchComponent extends Slim {
  isLoading = false;
  data = null;
  error = null;

  async fetchData(url, retries = 3, delay = 1000) {
    this.isLoading = true;
    this.error = null;
    for (let attempt = 1; attempt <= retries; attempt++) {
      try {
        const response = await fetch(url);
        if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
        this.data = await response.json();
        this.isLoading = false;
        return;
      } catch (err) {
        this.error = err.message;
        if (attempt < retries) {
          await this.sleep(delay * attempt);
        } else {
          this.isLoading = false;
          throw err;
        }
      }
    }
  }

  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

customElements.define('fetch-component', FetchComponent);

В этом примере:

  • fetchData выполняет запрос и автоматически повторяет его при ошибке.
  • Экспоненциальная задержка реализуется умножением базового интервала на номер попытки.
  • Состояния isLoading, data и error обновляются реактивно, что позволяет автоматически рендерить компонент.

Расширенные стратегии Retry

Помимо простого фиксированного количества попыток, Slim.js позволяет создавать более сложные стратегии:

  1. Retry с экспоненциальной задержкой и jitter Добавление случайного разброса (jitter) к задержке помогает избежать коллизий при одновременных запросах:
const jitter = Math.random() * 100;
await this.sleep(delay * attempt + jitter);
  1. Retry по типу ошибки Не все ошибки требуют повторной попытки. Можно фильтровать их по статусу:
if (![502, 503, 504].includes(err.status)) break;
  1. Retry с отменой Slim.js поддерживает реактивные флаги для отмены запроса, если компонент был размонтирован или пользователь отменил действие:
if (this.cancelled) break;

Обработка ошибок и уведомление состояния

Важная часть retry — корректное уведомление о состоянии запроса. Slim.js использует реактивные свойства для этого:

  • isLoading — индикатор процесса запроса.
  • error — текст ошибки после неудачных попыток.
  • data — результат успешного запроса.

Дополнительно можно реализовать событие для внешнего слушателя:

this.dispatchEvent(new CustomEvent('fetch-error', { detail: this.error }));

Интеграция с компонентами

Retry и обработка ошибок полностью интегрируются с жизненным циклом Slim.js-компонентов:

  • onBeforeMount — можно инициировать первый запрос.
  • onBeforeUnmount — прерывание активных retry-запросов.
  • render — реактивно отображает состояния isLoading, error и data.

Примеры практического применения

  • Повторные запросы к REST API при временных сетевых сбоях.
  • Автоматическая перезагрузка данных при сбое WebSocket-подключения.
  • Фоновая синхронизация данных с сервером с защитой от перегрузки сети.

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