Прерывание цепочки выполнения

В Universal Router каждая запись маршрута может содержать асинхронный или синхронный обработчик (action), который возвращает значение. Механизм выполнения маршрутов основан на последовательном обходе дерева маршрутов: при совпадении пути роутер вызывает соответствующий action и переходит к следующему уровню вложенности. Иногда необходимо прервать дальнейшее выполнение цепочки, чтобы вернуть результат немедленно или остановить обработку дочерних маршрутов. Universal Router предоставляет несколько способов для этого.


Возврат значения из action

Основной способ прерывания цепочки — возврат значения из функции action. Если функция возвращает не undefined, выполнение маршрутизации останавливается, и возвращенное значение становится результатом маршрута.

import UniversalRouter from 'universal-router';

const routes = [
  {
    path: '/dashboard',
    action: () => {
      return 'Dashboard загружен';
    }
  },
  {
    path: '/profile',
    action: () => {
      return 'Профиль пользователя';
    }
  }
];

const router = new UniversalRouter(routes);

router.resolve('/dashboard').then(result => {
  console.log(result); // 'Dashboard загружен'
});

Ключевой момент: action автоматически прерывает цепочку, если возвращает любое значение, отличное от undefined.


Использование next() для делегирования

Функция next в action позволяет передавать управление следующему маршруту. Если next() вызывается без аргументов, выполнение продолжается, иначе возвращаемое значение становится результатом маршрута.

const routes = [
  {
    path: '/user/:id',
    action: (context, next) => {
      if (context.params.id === 'admin') {
        return 'Администратор';
      }
      return next(); // Продолжаем поиск среди дочерних маршрутов
    },
    children: [
      { path: '', action: () => 'Обычный пользователь' }
    ]
  }
];

const router = new UniversalRouter(routes);
router.resolve('/user/admin').then(console.log); // 'Администратор'
router.resolve('/user/guest').then(console.log); // 'Обычный пользователь'

Особенность: вызов next() с аргументом немедленно завершает обработку и возвращает переданное значение.


Прерывание с помощью исключений

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

class RouteAbort extends Error {
  constructor(message) {
    super(message);
    this.name = 'RouteAbort';
  }
}

const routes = [
  {
    path: '/secret',
    action: () => {
      throw new RouteAbort('Доступ запрещён');
    }
  }
];

const router = new UniversalRouter(routes);

router.resolve('/secret')
  .then(console.log)
  .catch(error => {
    if (error instanceof RouteAbort) {
      console.error(error.message); // 'Доступ запрещён'
    }
  });

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


Прерывание вложенных маршрутов

Вложенные маршруты также поддерживают прерывание. Если родительский action возвращает значение, дочерние маршруты не выполняются:

const routes = [
  {
    path: '/products',
    action: () => 'Список товаров',
    children: [
      { path: ':id', action: () => 'Детали товара' }
    ]
  }
];

const router = new UniversalRouter(routes);

router.resolve('/products').then(console.log); // 'Список товаров'
router.resolve('/products/42').then(console.log); // 'Детали товара'

Если в родительском action вернуть значение, вложенный маршрут не будет вызван:

const routes = [
  {
    path: '/products',
    action: () => 'Прерываем обработку',
    children: [
      { path: ':id', action: () => 'Детали товара' }
    ]
  }
];

router.resolve('/products/42').then(console.log); // 'Прерываем обработку'

Асинхронное прерывание

Universal Router полностью поддерживает прерывание в асинхронных обработчиках. Если action возвращает промис, маршрутизация ожидает его разрешения, после чего цепочка может быть прервана:

const routes = [
  {
    path: '/load',
    async action() {
      const data = await fetchData();
      if (!data) return 'Данные отсутствуют'; // Прерывание цепочки
      return 'Данные загружены';
    }
  }
];

router.resolve('/load').then(console.log);

Практические советы

  • Использовать return next() для продолжения маршрутизации только в случаях, когда родительский маршрут не полностью обработал путь.
  • Возврат значения из action — простой способ остановки маршрутизации.
  • Исключения — полезны для обработки ошибок или защиты маршрутов.
  • Вложенные маршруты выполняются только если родительский action вернул undefined или вызвал next().
  • Асинхронные операции полностью интегрированы в цепочку маршрутизации, поэтому можно безопасно возвращать промисы.

Прерывание цепочки является основным механизмом контроля маршрутизации в Universal Router, позволяя гибко управлять обработкой как простых, так и сложных вложенных маршрутов.