В библиотеке Page.js маршруты управляются с помощью цепочек функций-обработчиков, которые вызываются при совпадении URL. Каждый маршрут может содержать несколько обработчиков, выполняющихся последовательно. Понимание порядка их выполнения критично для построения корректной логики приложения.
Обработчики регистрируются с помощью метода
page(path, handler1, handler2, ...). Порядок передачи
функций определяет порядок их вызова. Пример:
page('/dashboard', checkAuth, loadData, renderDashboard);
В этом примере:
checkAuth проверяет авторизацию пользователя.loadData загружает необходимые данные.renderDashboard отвечает за отображение страницы.Важно: каждый последующий обработчик вызывается
только после вызова функции next() предыдущим
обработчиком.
Функция next() передаётся в каждый обработчик
автоматически. Если она не вызывается, выполнение цепочки
останавливается.
function checkAuth(ctx, next) {
if (!ctx.user) {
page.redirect('/login');
} else {
next();
}
}
В примере выше, если пользователь не авторизован, next()
не вызывается, и последующие обработчики (loadData,
renderDashboard) не выполняются.
Page.js поддерживает глобальные middleware, которые выполняются для всех маршрутов:
page('*', globalLogger);
Глобальные обработчики всегда вызываются перед обработчиками конкретного маршрута.
Порядок вызова:
page().Обработчики могут выполнять асинхронные операции. Для корректного
порядка важно вызвать next() после завершения асинхронного
кода:
function loadData(ctx, next) {
fetch('/api/data')
.then(response => response.json())
.then(data => {
ctx.data = data;
next();
});
}
Если next() вызвать до завершения загрузки данных,
последующий обработчик получит пустой контекст.
Если несколько маршрутов совпадают с одним URL,
Page.js выполняет первый зарегистрированный маршрут,
полностью проходя его обработчики, и останавливается, если внутри
обработчиков не используется next().
page('/profile', auth, renderProfile);
page('/profile/settings', auth, renderSettings);
При переходе на /profile/settings выполняются
обработчики маршрута /profile/settings. Обработчики
/profile не выполняются, так как URL отличается, даже
несмотря на частичное совпадение.
Можно намеренно прервать выполнение обработчиков, например, при ошибке или при редиректе:
function checkAdmin(ctx, next) {
if (!ctx.user.isAdmin) {
page.redirect('/not-authorized');
return; // Прерываем цепочку
}
next();
}
Без return выполнение могло бы продолжиться и вызвать
нежелательные эффекты.
Для сложных приложений часто создают цепочки middleware для разных уровней маршрутов:
page('/app', auth, layout);
page('/app/dashboard', loadDashboard, renderDashboard);
page('/app/settings', loadSettings, renderSettings);
auth выполняется для всех маршрутов
/app*.layout отвечает за общий каркас приложения.Такой подход позволяет структурировать обработчики по уровням ответственности.
Контекст (ctx) передаётся всем обработчикам маршрута и
глобальным middleware. Можно хранить данные для последующих
обработчиков:
function auth(ctx, next) {
ctx.user = getCurrentUser();
next();
}
function loadDashboard(ctx, next) {
ctx.dashboardData = fetchDashboard(ctx.user.id);
next();
}
function renderDashboard(ctx) {
renderTemplate('dashboard', ctx.dashboardData);
}
Использование контекста обеспечивает последовательное накопление данных без глобальных переменных.
Порядок выполнения обработчиков в Page.js определяется:
page('*', handler)).page('/path', handler1, handler2)).next() внутри обработчиков.ctx.Правильное управление этим порядком позволяет создавать сложные маршруты с логической последовательностью действий и безопасной обработкой ошибок.