Мій API відповів за 4 мс, але навігація все одно здавалася повільною
Я займався налагодженням застосунку для управління проєктами, побудованого на SvelteKit та Rust API.
На моєму локальному комп'ютері все працювало миттєво. На VPS навігація здавалася важкою. Відкриття таких сторінок, як Tickets або Timeline, займало занадто багато часу. Натискання на тікет викликало помітну затримку перед появою попереднього перегляду.
Я думав, що проблема в сервері. Я підозрював повільні запити до бази даних або слабкий VPS.
Вимірювання довели мою неправоту.
Я перевірив endpoint списку функцій. Для лише 52 тікетів API відповів за 4 мс. Це звучить швидко. Але розмір відповіді становив 354 КБ.
Payload маршруту SvelteKit демонстрував ту саму проблему. Обсяг даних був величезним для простого списку.
Проблема була не в швидкості. Проблема була у вазі.
Описи самі по собі складали 80% загальної відповіді. Endpoint списку повертав повні описи у форматі Markdown для кожного окремого елемента.
Це поширена пастка. Endpoint списку перетворився на endpoint деталей. Щоразу, коли сторінці був потрібен список, вона платила ціну за дані, які не використовувала.
Використання в UI не визначає payload. Його визначає структура даних, яку повертає loader.
Якщо ваш loader повертає повний об'єкт, SvelteKit серіалізує весь цей об'єкт у дані маршруту. Навіть якщо ви ніколи не рендерите певне поле, воно все одно передається через мережу.
Я виправив це, відокремивши підсумкові дані від детальних.
Я створив два різні контракти:
• Контракт списку для підсумків (ID, title, status, dates). • Контракт деталей для повної інформації (descriptions, commands).
Я розділив API на два endpoints:
- GET /features (повертає підсумки)
- GET /features/:id (повертає одну повну деталь)
Я також змінив принцип роботи фронтенду. Тепер застосунок миттєво рендерить список, використовуючи підсумкові дані. Коли ви натискаєте на тікет, застосунок показує «оболонку» (shell) і завантажує важкі детальні дані у фоновому режимі.
Результати були вражаючими:
• API списку функцій: скорочення на 89,6% • Дані маршруту Tickets: скорочення на 91,4% • API документації OpenSpec: скорочення на 98,9%
База даних завжди була швидкою. Справжнім вузьким місцем був контракт даних між API та сторінкою.
Уроки для застосунків із великою кількістю списків:
- Вимірюйте розмір відповіді, а не лише час відповіді.
- Розглядайте дані для списків та детальної інформації як окремі сутності.
- Ніколи не повертайте великі текстові поля у представленні списку.
- Перевірте, що саме серіалізує ваш SSR-завантажувач.
- Використовуйте ліниве завантаження для детальних даних, але миттєво відображайте каркас інтерфейсу (UI shell).
- Не використовуйте індикатор завантаження, щоб приховати важке корисне навантаження.
Швидкий запит не гарантує швидкої роботи сторінки.
Джерело: https://dev.to/ahikmah/my-api-responded-in-4-ms-but-navigation-still-felt-slow-1hk8