Web Performance

Защо сайтът ви трябва да изпраща по-малко заявки, а не просто по-малки

Малките файлове не са безплатни. Съвременният HTTP намали разхода на заявките, но не го направи незначителен.

The Wux Webtools Team The Wux Webtools Team 2 мин четене С подкрепа от ИИ, прегледано от човек
A stylized browser waterfall showing many small requests simplified into fewer intentional requests.
Съдържание
  1. Удобният мит за „просто направете всеки файл по-малък“
  2. Заявките не са само байтове
  3. „Но HTTP/2 реши това“ — в повечето случаи не
  4. Waterfall диаграмата е мястото, където живее истината
  5. По-малките файлове все още имат значение — просто не еднакво
  6. Скритите разходи на многото малки файлове
  7. 1. Късно откриване
  8. 2. Разход за headers
  9. 3. Прекъсване на main thread
  10. 4. Сложност на cache
  11. Bundling се завръща, но с преценка
  12. Заявките към трети страни заслужават допълнително подозрение
  13. Практичен списък за намаляване на заявките
  14. Премахнете
  15. Комбинирайте обмислено
  16. Отложете
  17. Cache-вайте правилно
  18. Измерете отново
  19. Как изглежда доброто състояние

Удобният мит за „просто направете всеки файл по-малък“

Години наред съветите за уеб производителност звучаха просто: компресирайте всичко, минифицирайте всичко, направете всеки ресурс по-малък.

Този съвет все още е до голяма степен правилен. Скрипт от 40 KB обикновено е по-добър от скрипт от 400 KB. Оптимизирано изображение е по-добро от суров експорт. Brotli, AVIF, CSS minification, tree shaking и font subsetting — всички те имат значение.

Но в много продукционни сайтове по-големият проблем вече не е един прекалено голям файл. Проблемът е броят неща, които браузърът трябва да поиска, преди страницата да започне да се усеща използваема.

Една страница може да изглежда дисциплинирана по отношение на размерите на файловете и въпреки това да е бавна, защото изпраща 120 заявки: CSS фрагменти, JavaScript chunks, тагове от трети страни, файлове с шрифтове, tracking pixels, icon sprites, JSON endpoints, preloads, analytics beacons и cache revalidations. Всяко от тях може да е „малко“. Заедно те създават дълга и крехка waterfall диаграма.

Практичното правило е следното: щом отделните ресурси са разумно компресирани, намаляването на броя заявки често подобрява потребителското преживяване повече от спестяването на няколко килобайта от всеки файл.

Заявките не са само байтове

Една мрежова заявка не е само прехвърляне на данни. Тя е поредица от действия.

Браузърът трябва да открие ресурса, да реши кога да го изтегли, да го насрочи спрямо други ресурси, да изпрати headers, да изчака сървъра, да получи headers, да анализира отговора, често да го декомпресира и след това да направи нещо полезно с него.

Това „нещо полезно“ може да бъде скъпо. JavaScript файл трябва да бъде parsed, compiled и executed. CSS файл може да блокира rendering. Файл с шрифт може да забави четимия текст или да причини layout shifts. Изображение може да засегне елемента за Largest Contentful Paint. Скрипт от трета страна може да донесе собствена верига от зависимости.

Затова броят заявки все още има значение, дори когато файловете са малки. Скрипт от 3 KB може да е по-лош от изображение от 30 KB, ако блокира rendering, пристига късно и се изпълнява в main thread в неподходящия момент.

Ако четете Lighthouse report и се чувствате наказани от десетки отделни предупреждения, започнете с request waterfall, вместо с отделните оценки. Имаме практическо ръководство в how to read a Lighthouse report without panicking, но кратката версия е: намерете какво блокира първия render и какво забавя основното съдържание.

„Но HTTP/2 реши това“ — в повечето случаи не

HTTP/2 и HTTP/3 промениха икономиката на заявките. Те въведоха multiplexing, header compression и по-добро поведение на връзките. Казано просто, браузърите станаха много по-добри в изпращането на множество заявки през по-малко връзки.

Това беше реално подобрение. То също така сложи край на някои стари навици, като крайни CSS sprites и огромни concatenated bundles, създавани само за да се избегнат ограниченията на връзките.

Но HTTP/2 не направи заявките безплатни.

Multiplexing помага, когато много ресурси споделят една връзка, но браузърът все още трябва да ги приоритизира. Сървърите все още трябва да отговарят. Клиентът все още трябва да обработи всеки отговор. Congestion, packet loss, TLS negotiation, DNS lookup, cache misses и натиск върху main thread все още съществуват.

HTTP/3 подобрява част от transport поведението, особено около connection migration и head-of-line blocking на transport layer. Той не премахва разхода за откриване, насрочване, изтегляне, parsing и изпълнение на ресурси.

Затова съвременната цел не е „съберете всичко в един огромен файл“. Тя е „изпращайте по-малко критични заявки и направете останалите заявки целенасочени“.

Waterfall диаграмата е мястото, където живее истината

Проблемите с производителността рядко се обявяват в една-единствена метрика. Те се проявяват като форма.

Отворете network panel в браузъра и погледнете първите няколко секунди. Попитайте:

  • Колко заявки започват преди да се появи основното съдържание?
  • Кои заявки блокират rendering?
  • Важни ресурси откриват ли се късно?
  • Скриптове от трети страни конкурират ли се с first-party CSS, шрифтове или изображения?
  • Много файлове връщат ли 304 responses, вместо да се обслужват директно от cache?
  • Икони, шрифтове или UI фрагменти разделени ли са на повече файлове, отколкото страницата изисква?

Бързата страница обикновено има скучна ранна waterfall диаграма. Малък брой критични ресурси пристигат рано. Некритичните ресурси изчакват. Скриптовете от трети страни са забавени, ограничени или премахнати. Браузърът не е принуден да жонглира с двадесет приоритета, преди да може да изрисува страницата.

Бавната страница често има нервна waterfall диаграма: много малки файлове, много origins и много късни откривания.

По-малките файлове все още имат значение — просто не еднакво

Това не е аргумент срещу компресията или оптимизацията. Това е аргумент срещу оптимизирането на байтове, докато координацията се пренебрегва.

По-малките файлове имат най-голямо значение, когато ресурсът е голям, render-blocking или част от пътя към основното съдържание. Например:

  • Hero изображението трябва да бъде с правилен размер и кодиране.
  • Render-blocking CSS трябва да бъде лек.
  • JavaScript, необходим за първото взаимодействие, трябва да бъде минимален.
  • Шрифтовете трябва да бъдат subset, компресирани и ограничени до реално използваните weights.

Шрифтовете са често срещан пример. Екипите често се вторачват в това дали файл с шрифт е 24 KB или 31 KB, докато изпращат шест weights, два styles и няколко families. По-доброто решение не е да се изстискат 7 KB от един файл. То е да се изпращат по-малко файлове с шрифтове. Ако typography е част от работата ви по производителност, web fonts are still one of the easiest wins on most sites.

Изображенията следват същия модел. AVIF или WebP могат да спестят значими байтове, но изпращането на десет декоративни изображения above the fold все още е лош план. Избирайте по-добри формати, да, но също така поставяйте под въпрос дали всяко изображение изобщо трябва да бъде заявено. За решения относно форматите нашето ръководство when AVIF beats WebP and when it does not е полезно допълнение към тази работа по броя заявки.

Скритите разходи на многото малки файлове

Многото малки заявки обикновено създават проблеми, които не се виждат, ако гледате само общия обем прехвърлени байтове.

1. Късно откриване

Браузърите не могат да заявят това, което не са открили. CSS файл може да реферира шрифт. Скрипт може да import-не друг скрипт. Компонент може да заяви JSON след hydration. Всяка зависимост създава още една стъпка във веригата.

Колкото по-дълбока е веригата, толкова по-късно започва важната работа.

2. Разход за headers

Всяка заявка и всеки отговор включват headers. Header compression помага, особено през HTTP/2 и HTTP/3, но не премахва разхода. Cookies могат значително да влошат това. Ако сайтът ви изпраща големи cookies с всяка заявка, малките ресурси на практика стават по-малко малки.

Това е една от причините статичните ресурси често да трябва да живеят на пътища или домейни без cookies и защо cache headers заслужават внимание. Ако headers се държат странно в production, debugging redirects and HTTP headers обикновено е по-бързо от гадаенето.

3. Прекъсване на main thread

Много JavaScript chunks могат да създадат повтаряща се работа по parsing и изпълнение. Дори всеки chunk да е малък, браузърът може постоянно да спира, за да оценява код. Това може да навреди на Interaction to Next Paint и да направи страницата да се усеща нестабилна.

Потребителят не се интересува, че всеки файл е бил малък. Интересува се, че докосването на меню е отнело 600 милисекунди.

4. Сложност на cache

Разделянето на ресурси може да подобри caching, когато се прави внимателно. Стабилен vendor bundle и променящ се app bundle могат да бъдат добро разделяне.

Но прекомерното chunking може да има обратен ефект. Повече файлове означават повече cache lookups, повече възможности за revalidation, повече координация на версии и повече начини случайно да инвалидираш ресурси, които не е трябвало да се променят.

Bundling се завръща, но с преценка

Първата ера на уеб производителността обичаше bundling, защото браузърите имаха строги ограничения за връзките. После дойде HTTP/2 и много екипи рязко се насочиха към агресивно code splitting. Част от това беше полезно. Част се превърна в суеверие.

Разумната среда е route-aware bundling.

За типичен marketing site или content site:

  • Inline-нете или заредете само CSS, необходим за първоначалното rendering.
  • Дръжте global JavaScript малък.
  • Избягвайте разделянето на tiny modules в отделни мрежови заявки.
  • Отложете интерактивни функции, които не са нужни веднага.
  • Премахнете скриптове от трети страни, които не оправдават разхода си.

За приложение:

  • Разделяйте по route или major feature, не по всеки компонент.
  • Поддържайте shared dependencies стабилни и cacheable.
  • Preload-вайте само ресурси, които със сигурност ще бъдат нужни скоро.
  • Избягвайте зареждането на admin, dashboard, editor или experiment code на публични страници.
  • Измервайте разхода за interaction, не само bundle size.

Bundling не е автоматично добър. Code splitting не е автоматично добър. Полезният въпрос е: помага ли това разделяне на браузъра да достави следващото значимо потребителско преживяване по-рано?

Заявките към трети страни заслужават допълнително подозрение

First-party заявките поне са под ваш контрол. Заявките към трети страни често са по-бавни, по-малко предвидими и по-скъпи, отколкото изглеждат.

Един tag manager може да задейства analytics, ads, heatmaps, chat widgets, A/B testing, consent tools и personalization scripts. Всеки vendor може да донесе още заявки. Някои ще се изпълнят рано. Някои ще блокират main thread. Някои ще се променят без вашия release process.

Най-добрата оптимизация на трети страни е изтриването. Втората най-добра е отлагането.

Преди да добавите скрипт от трета страна, попитайте:

  • Трябва ли това да се зареди, преди потребителят да види страницата?
  • Трябва ли да се зарежда на всяка страница?
  • Може ли да се зареди след consent, interaction или idle time?
  • Кой го притежава вътрешно?
  • Коя метрика доказва, че си струва разхода за производителност?

Тук производителността се превръща в governance. Някой трябва да има право да каже „не“.

Практичен списък за намаляване на заявките

Започнете със страниците, които имат най-голямо значение: homepage, pricing page, product page, checkout, signup или top landing pages. След това преминете през waterfall диаграмата.

Премахнете

  • Изтрийте неизползван JavaScript и CSS.
  • Премахнете стари experiments, изоставени pixels и дублираща се analytics.
  • Махнете неизползвани font weights и icon libraries.
  • Заменете декоративни изображения с CSS, когато е подходящо.

Комбинирайте обмислено

  • Bundle-вайте малки JavaScript modules, които винаги се зареждат заедно.
  • Обединявайте малки CSS файлове, които блокират един и същ render path.
  • Използвайте SVG sprites или inline SVG за повтарящи се икони, когато това намалява заявките, без да вреди на maintainability.

Отложете

  • Lazy-load-вайте изображения below the fold.
  • Отлагайте некритични скриптове до след first paint или user interaction.
  • Зареждайте comments, embeds, maps, chat и video players само когато са нужни.

Cache-вайте правилно

  • Използвайте long-lived caching за versioned static assets.
  • Избягвайте ненужна revalidation за файлове, които рядко се променят.
  • Дръжте HTML свеж, но оставете hashed assets да останат cached.

Измерете отново

След всяка промяна проверете waterfall диаграмата отново. Целта не е перфектен резултат. Целта е по-малко критични заявки, по-ранно полезно rendering и по-малко смущения в main thread.

Как изглежда доброто състояние

Здравата страница не е задължително тази с възможно най-малко заявки. Тя има малък и целенасочен critical path.

Браузърът получава HTML, essential CSS, изображението за основното съдържание, ако има такова, може би малък скрипт, необходим за navigation или interaction above the fold, и минималния набор шрифтове, нужен текстът да бъде четим. Всичко останало чака реда си.

Това е разликата между страница, която е просто оптимизирана, и страница, която се усеща бърза.

Свиването на файловете все още си струва. Но ако сайтът вече е разумно компресиран, следващата печалба в производителността обикновено не е още 2 KB, спестени от bundle. Тя е една блокираща заявка по-малко, един файл с шрифт по-малко, един скрипт от трета страна по-малко, една верига от зависимости по-малко.

По-малкото заявки правят работата на браузъра по-проста. А простото е бързо по-често, отколкото обичаме да признаваме.

Често задавани въпроси

Един голям bundle по-добър ли е от много малки файлове?
Не автоматично. Един огромен bundle може да забави всичко, особено при първо зареждане. Много малки файлове могат да създадат разход за насрочване и изпълнение. По-добрият модел е да bundle-вате ресурси, които винаги са нужни заедно, и да разделяте по route или major feature.
Означава ли HTTP/2, че броят заявки вече няма значение?
Не. HTTP/2 намалява част от разхода за връзки чрез multiplexing и header compression, но всяка заявка все още има разходи за откриване, приоритизация, сървър, cache, parsing и изпълнение.
Трябва ли да inline-на целия critical CSS?
Inline-ването на малко количество наистина critical CSS може да помогне за first render, но прекаленото inline-ване прави HTML по-тежък и по-труден за cache. Дръжте го минимален и измервайте ефекта.
Къде е най-лесно да се намалят заявките?
Шрифтовете и скриптовете от трети страни често са най-бързите победи. Много сайтове изпращат неизползвани font weights, дублираща се analytics, стари pixels, chat widgets или embeds, които не е нужно да се зареждат веднага.
Колко заявки трябва да има една страница?
Няма универсална цел. Малка content page трябва да има много малко критични заявки. Сложно приложение може да се нуждае от повече. Фокусирайте се върху намаляване на заявките преди first render и преди основния interaction path.

Източници и допълнително четене

  1. MDN Web Docs: HTTP caching
  2. web.dev: Optimize Largest Contentful Paint
  3. RFC 9113: HTTP/2
  4. HTTP Archive Web Almanac: Page Weight
За автора
The Wux Webtools Team

Последно обновление:

Продължете да четете