Navigo — это лёгкий роутер для JavaScript, ориентированный на работу с одностраничными приложениями (SPA). Одной из ключевых особенностей является возможность композиции обработчиков, позволяющей структурировать логику маршрутов, объединять повторяющиеся действия и управлять сложными сценариями навигации.
Композиция обработчиков позволяет разделять ответственность между функциями и создавать цепочки действий, которые выполняются при совпадении маршрута. В основе этого лежит функциональный подход: каждый обработчик является функцией, принимающей объект параметров маршрута, контекст или состояние приложения.
Базовый обработчик в Navigo выглядит следующим образом:
const router = new Navigo('/');
function showHome() {
console.log('Главная страница');
}
router.on('/', showHome);
В этом случае обработчик showHome выполняется при
переходе на /. Для композиции важно понимать, что
обработчик — это обычная функция, которую можно оборачивать,
комбинировать или цеплять с другими функциями.
Композиция обработчиков часто реализуется через промежуточные функции. Это функции, которые выполняются до основного обработчика и могут изменять параметры, проверять авторизацию, логировать действия или выполнять асинхронные задачи.
Пример реализации промежуточной функции:
function authMiddleware(params, next) {
if (user.isAuthenticated) {
next(); // передаём управление следующей функции
} else {
router.navigate('/login');
}
}
function logMiddleware(params, next) {
console.log('Навигация на маршрут:', params);
next();
}
function showDashboard() {
console.log('Панель управления');
}
router.on('/dashboard', (params, query) => {
authMiddleware(params, () => {
logMiddleware(params, showDashboard);
});
});
В этом примере каждый middleware получает управление и может
передать его следующей функции через next. Такой
подход позволяет создавать цепочки функций без дублирования кода.
Более удобный способ — создание утилиты для объединения нескольких функций в одну цепочку:
function composeHandlers(...handlers) {
return function(params) {
let index = -1;
function next() {
index++;
if (index < handlers.length) {
handlers[index](params, next);
}
}
next();
}
}
function middlewareA(params, next) {
console.log('Middleware A');
next();
}
function middlewareB(params, next) {
console.log('Middleware B');
next();
}
function finalHandler(params) {
console.log('Основной обработчик', params);
}
router.on('/composed', composeHandlers(middlewareA, middlewareB, finalHandler));
В этом коде composeHandlers позволяет объединять
несколько функций в один единый обработчик, сохраняя
порядок выполнения и контроль передачи управления.
Navigo поддерживает асинхронные функции. При композиции асинхронных
обработчиков важно использовать async/await или
промисы, чтобы правильно ожидать завершения каждой функции
перед переходом к следующей:
async function fetchData(params, next) {
const data = await fetch(`/api/data/${params.id}`).then(res => res.json());
params.data = data;
next();
}
async function showData(params) {
console.log('Данные:', params.data);
}
router.on('/data/:id', composeHandlers(fetchData, showData));
Здесь данные загружаются асинхронно, и только после успешного завершения запроса вызывается основной обработчик.
next, тем легче отлаживать цепочку.params и, при
необходимости, модифицировать его.(params, next) для совместимости с
утилитой композиции.В больших приложениях рекомендуется строить модульные цепочки, где:
Такой подход делает код масштабируемым, читаемым и легко тестируемым, что особенно важно для SPA с большим количеством маршрутов и динамическим контентом.