Обработка ошибок в контроллерах

Контроллеры Stimulus выполняют ключевую роль в связывании JavaScript с HTML-элементами, однако при работе с динамическим контентом и асинхронными операциями неизбежно возникают ошибки. Эффективная обработка ошибок повышает надежность приложения и упрощает отладку.


Основные источники ошибок

  1. Ошибки в методах действий (actions) Любой метод контроллера, привязанный к событию через data-action, может завершиться с исключением. Примеры типичных проблем:

    • Отсутствие ожидаемого элемента DOM.
    • Ошибки в логике обработки данных.
    • Некорректная работа с асинхронными операциями.
  2. Ошибки при работе с targets Если контроллер ожидает наличие определённого элемента через this.hasTargetNameTarget или this.targetNameTarget, его отсутствие приведет к выбросу исключения ReferenceError.

  3. Ошибки асинхронного кода Использование fetch, async/await и промисов требует явной обработки ошибок через try/catch или catch на промисе. Необработанные промисы вызывают непредсказуемое поведение приложения.


Встроенные возможности обработки

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

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["output"]

  async submit(event) {
    event.preventDefault()
    try {
      const response = await fetch("/api/data", { method: "POST" })
      if (!response.ok) throw new Error(`Ошибка сервера: ${response.status}`)
      const data = await response.json()
      this.outputTarget.textContent = data.message
    } catch (error) {
      this.handleError(error)
    }
  }

  handleError(error) {
    console.error("Произошла ошибка в контроллере:", error)
    this.outputTarget.textContent = "Произошла ошибка, попробуйте снова"
  }
}

Особенности подхода:

  • Используется try/catch для асинхронных методов.
  • Выделен отдельный метод handleError, что упрощает повторное использование и унификацию отображения ошибок.
  • Ошибки логируются в консоль и выводятся пользователю безопасным способом.

Проверка наличия targets и values

Для предотвращения ReferenceError рекомендуется использовать проверку через свойства hasTargetNameTarget или hasValueNameValue:

if (this.hasOutputTarget) {
  this.outputTarget.textContent = "Данные обновлены"
} else {
  console.warn("Target output отсутствует")
}

Проверка значений через hasValueNameValue аналогична, что особенно важно при работе с динамически задаваемыми параметрами.


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

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

function safeAction(action) {
  return async function(event) {
    try {
      await action.call(this, event)
    } catch (error) {
      if (typeof this.handleError === "function") {
        this.handleError(error)
      } else {
        console.error(error)
      }
    }
  }
}

export default class extends Controller {
  static targets = ["output"]

  connect() {
    this.performAction = safeAction(this.performAction)
  }

  async performAction(event) {
    // Логика метода
  }

  handleError(error) {
    this.outputTarget.textContent = "Ошибка при выполнении действия"
  }
}

Такой подход позволяет минимизировать дублирование try/catch в каждом методе.


Взаимодействие с сервером и статусами ошибок

При работе с серверными API важно обрабатывать коды состояния HTTP:

async fetchData() {
  try {
    const response = await fetch("/api/items")
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`)
    }
    const items = await response.json()
    this.renderItems(items)
  } catch (error) {
    this.handleError(error)
  }
}

Отдельное внимание уделяется:

  • Проверке response.ok для выявления ошибок сервера.
  • Логированию подробной информации для отладки.

Логирование и уведомление

Обработка ошибок в контроллерах Stimulus часто включает:

  • Консольное логирование для разработчика (console.error, console.warn).
  • UI-уведомления для пользователя (например, изменение текста, отображение модального окна).
  • Возможность интеграции с внешними сервисами мониторинга (Sentry, LogRocket) через метод handleError.

Рекомендации по архитектуре

  • Все асинхронные действия должны быть обернуты в try/catch.
  • Проверять наличие всех ожидаемых targets перед доступом к ним.
  • Создать универсальный метод handleError для всех контроллеров, чтобы унифицировать обработку.
  • Логировать ошибки с достаточной детализацией без раскрытия чувствительной информации пользователю.
  • При взаимодействии с сервером обрабатывать все коды статуса HTTP и корректно реагировать на ошибки.

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