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

В Page.js маршруты обрабатываются последовательно, создавая цепочку функций-обработчиков. Иногда возникает необходимость остановить дальнейшее выполнение цепочки, например, когда обработка определённого маршрута уже завершена или когда требуется перенаправление пользователя. Для этого используются встроенные механизмы next() и return.


Функция next()

Каждый обработчик маршрута получает первым аргументом объект контекста, а вторым — функцию next. Вызов next() передаёт управление следующему обработчику, зарегистрированному для данного маршрута. Если next() не вызван, цепочка прерывается автоматически.

page('/dashboard', function(ctx, next) {
    if (!ctx.user.isLoggedIn) {
        page.redirect('/login');
        return; // Прерываем цепочку
    }
    next(); // Передаём управление следующему обработчику
});

page('/dashboard', function(ctx) {
    console.log('Пользователь авторизован, показываем панель');
});

В этом примере цепочка маршрута /dashboard прерывается, если пользователь не авторизован. Вызов page.redirect перенаправляет браузер, а return гарантирует, что последующие обработчики не будут вызваны.


Условное прерывание цепочки

Прерывание цепочки может быть условным, в зависимости от состояния приложения. Это полезно при аутентификации, проверке прав доступа или при загрузке данных.

page('/profile', function(ctx, next) {
    fetchUserData(ctx.user.id).then(data => {
        if (!data.exists) {
            page.redirect('/not-found');
        } else {
            ctx.userData = data;
            next(); // продолжаем цепочку
        }
    });
});

Ключевой момент: необходимо контролировать вызов next(), чтобы цепочка не зависла. Любое асинхронное действие должно корректно вызывать next() только после завершения проверки.


Прерывание с использованием page.redirect

Метод page.redirect(path) автоматически останавливает текущую цепочку маршрутов, инициируя переход к новому маршруту. Это особенно удобно для защиты маршрутов:

page('/admin', function(ctx, next) {
    if (!ctx.user.isAdmin) {
        page.redirect('/dashboard');
        return;
    }
    next();
});

page('/admin', function(ctx) {
    renderAdminPanel();
});

page.redirect выполняет три действия:

  1. Отменяет текущий маршрут.
  2. Запускает обработку нового маршрута.
  3. Гарантирует, что все последующие функции текущего маршрута не будут вызваны.

Использование return для остановки цепочки

Даже без перенаправления можно прервать цепочку простым return. Это особенно полезно для маршрутов с несколькими промежуточными функциями:

page('/shop', function(ctx, next) {
    if (!ctx.isOpen) return; // Магазин закрыт — не выполняем следующий обработчик
    next();
});

page('/shop', function(ctx) {
    renderShopItems();
});

Если условие срабатывает, next() не вызывается, и последующий обработчик не выполняется.


Цепочки с несколькими обработчиками

Page.js позволяет назначать несколько функций на один маршрут:

page('/settings', authGuard, loadSettings, renderSettings);

function authGuard(ctx, next) {
    if (!ctx.user.isLoggedIn) {
        page.redirect('/login');
        return;
    }
    next();
}

function loadSettings(ctx, next) {
    fetchSettings(ctx.user.id).then(settings => {
        ctx.settings = settings;
        next();
    });
}

function renderSettings(ctx) {
    render(ctx.settings);
}

В этом примере каждая функция имеет возможность прервать цепочку, либо передав управление дальше через next(). Такая организация позволяет модульно строить обработку маршрутов, разделяя проверки, загрузку данных и рендеринг.


Важные моменты при прерывании цепочки

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

Итоговый паттерн

Использование прерывания цепочки в Page.js часто выглядит так:

function handler(ctx, next) {
    if (условие_для_остановки) {
        page.redirect('/new-route'); // или return;
        return;
    }
    next();
}

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