𝗠𝗼𝗷𝗲 𝗔𝗣𝗜 𝗼𝗱𝗽𝗼𝘄𝗶𝗲𝗱𝘇𝗶𝗮ł𝗼 𝘄 𝟰 𝗺𝘀, 𝗯𝘂𝘁 𝗡𝗮𝘄𝗶𝗴𝗮𝗰𝗷𝗮 𝗪 𝗖𝘇𝘆𝗻𝗻𝗼ś𝗰𝗶 𝗪𝘆𝗱𝗮𝘄𝗮ł𝗮 𝗦𝗶𝗲 𝗦ł𝗼𝘄𝗮
Debugowałem aplikację do zarządzania projektami zbudowaną w SvelteKit z API w Rust.
Na moim lokalnym komputerze wszystko działało natychmiastowo. Na VPS nawigacja wydawała się ociężała. Otwieranie stron takich jak Tickets czy Timeline trwało zbyt długo. Kliknięcie w bilet powodowało zauważalne opóźnienie, zanim pojawił się podgląd.
Myślałem, że problem leży po stronie serwera. Podejrzewałem wolne zapytania do bazy danych lub słaby VPS.
Pomiary wykazały, że się myliłem.
Sprawdziłem endpoint listy funkcji. Dla zaledwie 52 biletów API odpowiedziało w 4 ms. Brzmi szybko. Ale rozmiar odpowiedzi wynosił 354 KB.
Payload trasy SvelteKit wykazywał ten sam problem. Rozmiar danych był ogromny jak na zwykłą listę.
Problemem nie była prędkość. Problemem była waga.
Same opisy stanowiły 80% całkowitej odpowiedzi. Endpoint listy zwracał pełne opisy w formacie Markdown dla każdego pojedynczego elementu.
To częsta pułapka. Endpoint listy stał się endpointem szczegółowym. Za każdym razem, gdy strona potrzebowała listy, płaciła cenę za dane, których nie używała.
Sposób wykorzystania danych w UI nie determinuje payloadu. Determinuje go struktura zwracana przez loader.
Jeśli Twój loader zwraca pełny obiekt, SvelteKit serializuje cały ten obiekt do danych trasy. Nawet jeśli nigdy nie renderujesz danego pola, i tak przesyłane jest ono przez sieć.
Naprawiłem to, oddzielając dane podsumowujące od danych szczegółowych.
Stworzyłem dwa różne kontrakty:
• Kontrakt listy dla podsumowań (ID, tytuł, status, daty). • Kontrakt szczegółowy dla pełnych informacji (opisy, polecenia).
Podzieliłem API na dwa endpointy:
- GET /features (zwraca podsumowania)
- GET /features/:id (zwraca jeden pełny szczegół)
Zmieniłem również sposób działania frontendu. Teraz aplikacja natychmiast renderuje listę, korzystając z danych podsumowujących. Po kliknięciu w bilet aplikacja wyświetla szkielet i pobiera ciężkie dane szczegółowe w tle.
Wyniki były ogromne:
• API listy funkcji: redukcja o 89,6% • Dane trasy biletów: redukcja o 91,4% • API dokumentacji OpenSpec: redukcja o 98,9%
Baza danych zawsze działała szybko. Prawdziwym wąskim gardłem był kontrakt danych między API a stroną.
Lekcje dla aplikacji opartych na dużych listach:
- Mierz rozmiar odpowiedzi, a nie tylko czas odpowiedzi.
- Traktuj payload listy i payload szczegółów jako osobne elementy.
- Nigdy nie zwracaj dużych pól tekstowych w widoku listy.
- Sprawdź, co tak naprawdę serializuje Twój loader SSR.
- Stosuj leniwe ładowanie danych szczegółowych, ale natychmiast wyświetlaj szkielet interfejsu (UI shell).
- Nie używaj spinnera ładowania, aby ukryć ciężki payload.
Szybkie zapytanie nie gwarantuje szybkiego działania strony.
Źródło: https://dev.to/ahikmah/my-api-responded-in-4-ms-but-navigation-still-felt-slow-1hk8