Universal Router — это гибкий и минималистичный роутер для JavaScript, который позволяет строить маршрутизацию как на клиентской, так и на серверной стороне. Одной из важнейших особенностей является возможность локальной обработки ошибок на уровне отдельных маршрутов, что обеспечивает изоляцию ошибок и предотвращает их всплытие в глобальный контекст.
error в маршрутеКаждый маршрут в Universal Router может содержать поле
action, которое возвращает либо результат маршрута, либо
промис. В случае возникновения ошибки внутри action, можно
определить локальный обработчик ошибок, используя поле
error в объекте маршрута:
const routes = [
{
path: '/profile',
action: async ({ params }) => {
if (!params.userId) {
throw new Error('User ID отсутствует');
}
return `Профиль пользователя ${params.userId}`;
},
error: ({ error, params }) => {
return `Ошибка на маршруте /profile: ${error.message}`;
}
}
];
const router = new UniversalRouter(routes);
router.resolve({ path: '/profile' })
.then(result => console.log(result))
.catch(err => console.error('Глобальная ошибка:', err));
Ключевые моменты:
error принимает объект с полями error,
params, pathname и другими, аналогичными тем,
что передаются в action.action конкретного маршрута.error возвращает значение, оно считается
результатом маршрута, и глобальный .catch не
вызывается.try/catch внутри actionИногда требуется более детальная обработка ошибок в самом действии
маршрута. Для этого можно использовать стандартный блок
try/catch:
{
path: '/dashboard',
action: async ({ params }) => {
try {
const data = await fetchData(params.dashboardId);
return renderDashboard(data);
} catch (err) {
return `Не удалось загрузить дашборд: ${err.message}`;
}
}
}
Этот подход позволяет:
Universal Router поддерживает вложенные маршруты, и
обработка ошибок может быть локальной для каждого уровня. Вложенный
маршрут может иметь собственный error:
const routes = [
{
path: '/app',
children: [
{
path: 'settings',
action: () => { throw new Error('Ошибка в настройках'); },
error: ({ error }) => `Ошибка в /app/settings: ${error.message}`
}
]
}
];
error срабатывает только для
ошибок, возникших в его action, если дочерний маршрут не
имеет своего error.Поскольку action может быть асинхронной функцией, важно
учитывать, что ошибки в промисах также перехватываются локальным
error:
{
path: '/data',
action: async () => {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error('Ошибка загрузки данных');
}
return response.json();
},
error: ({ error }) => `Ошибка получения данных: ${error.message}`
}
async action,
автоматически передается в локальный error.error для маршрутов, где можно предсказать
возможные ошибки.console.error или
специализированный сервис без вмешательства в поток маршрутизации.error должен быть автономным, иначе есть риск дублирования
сообщений об ошибках.error.try/catch внутри action,
если нужно превратить ошибку в контролируемый результат.Пример объединения всех подходов:
const routes = [
{
path: '/user/:id',
action: async ({ params }) => {
try {
const user = await getUser(params.id);
if (!user) throw new Error('Пользователь не найден');
return user;
} catch (err) {
throw err; // передаем ошибку локальному error
}
},
error: ({ error, params }) => {
return `Ошибка загрузки пользователя ${params.id}: ${error.message}`;
}
}
];
В этом примере:
getUser будет перехвачена локальным
обработчиком..catch не вызывается, так как локальный
обработчик возвращает результат.Локальная обработка ошибок в Universal Router позволяет строить устойчивую и предсказуемую маршрутизацию, где каждый маршрут самостоятельно управляет возможными сбоями без нарушения общей логики приложения.