• Strona główna
  • Curriculum Vitae
  • O mnie
  • Przykład: Gramatyka w PHP
  • Przykład: Kompresja CSS
  • Przykład: Kompresja JavaScript
  • Przykład: Skracanie linków
  • Przykład: Wykrywanie serwera HTTP
  • Przykład: Własna bramka SMS
  • Mapa strony
  • Kontakt
Niebieski Pomarańczowy Zielony Różowy Fioletowy

Minimalizacja zapytań HTTP

Opublikowane 4 kwietnia 2010. Autor: Kamil Brenk. Wizyt: 3 617.

Kategorie: Protokół HTTP
Tematyka: Across Domains, CSS, CSS Sprites, Image Maps, JavaScript, Minify CSS, Minify JavaScript, optymalizacja serwisów, Protokół HTTP, serwery wirtualne, URL scheme, współbieżność sieci, wydajność serwisów internetowych

kw. 04

Bardzo mnie denerwuje powolne się wczytywanie stron internetowych. Główny narzut czasowy stanowi zazwyczaj spora liczba obiektów do załadowania wraz ze stroną serwisu. Każdy obiekt powoduje wywołanie kolejnych zapytań HTTP. Efektem końcowym dla strony jest powolne wczytywanie zawartości.

Jak zminimalizować liczbę zapytań HTTP?

W czym problem?

Problem jest dość banalny. Im więcej wykonywanych jest zapytań HTTP, tym strona dłużej się wczytuje. Sprawa się jednak komplikuje, gdyż przeglądarki mają pewne ograniczenie – uniemożliwiają pobieranie wielu plików z tej samej domeny w tym samym czasie. W większości przeglądarek ograniczenie dotyczy dwóch różnych obiektów (plików).

Specyfikacja HTTP/1.0 umożliwia pobieranie maksymalnie 4 plików w jednym czasie z jednego hosta. HTTP/1.1 ogranicza już tylko do 2 plików.

W przypadku gdy strona musi wczytać więcej niż dwa obiekty, proces wygląda następująco: wczytywane są dwa pierwsze pliki i przeglądarka czeka na pobranie tych plików (nie nawiązuje kolejnych zapytań HTTP). Gdy zapytanie zostanie wykonane, pobierany jest kolejny plik, etc. Powoduje to pewne ograniczenie, gdyż użytkownicy szybszych łączy mogliby prędzej pobrać wszystkie obiekty, jednak są ograniczani przez ilość połączeń wykonywanych do jednej domeny. Jak to rozwiązać? O tym za chwilę. Tymczasem prezentuję kilka sposobów minimalizacji zapytań HTTP.

CSS Sprites

Metoda ta polega na łączeniu wielu plików graficznych w jeden większy, a następnie za pomocą CSS (pozycjonowania) wyświetlamy konkretne obszary grafiki bazowej. Dzięki temu zamiast wykonywać kilkanaście zapytań, możemy wykonać jedno zapytanie, a następnie odpowiednio pozycjonować pożądane obszary grafiki bazowej.

Image Maps

Technika ta polega na utworzeniu jednego dużego obrazu, a następnie za pomocą specjalnego elementu HTML (map) ustawiane są obszary, do których można przypiąć konkretne zdarzenia i akcje (odsyłacze). Jest to mniej wygodna technika minimalizacji zapytań HTTP, aczkolwiek czasem przydatna i ułatwiająca życie webmastera.

Kodowanie małych grafik

Kolejną metodą minimalizacji zapytań jest kodowanie niewielkiej wielkości grafik przy pomocy algorytmu base64, a następnie podstawianiu do elementów IMG HTML.

Wygląda to następująco:

1
<img src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAAAAAAAD5Q7t/AAADUUlEQVQ4ywXByU+cdRzA4c+7zPu+IFURFIqV0rwUIhqMpmriwWBsJaVNE2PsBkZLYuwf0HCyB88eDNE0sdakRr1pvFpr0qQk1iWYli7ADCNIpQPTGZjl927zLl+fR0srqYgDsS2ILmhxhCkaDytVCsVVtBS6e55i78BebCtH2ArQdR3LzpGkCWb2uE4iGQmCrcHN+Vv8MXeDrfJD9o+MUK5WuHLlZ0SE4yffZWpqEhEhTRIky9AqWSKGCJnyuP7LVR78+x9xAprdzoFXXsVTO1z+5jKFwhKlUokjRw4zM3OOvr4+LMtCK0skbYkwf20Ox7QpN33+XFym7IV4QUinhGysr1LI5+nr7eHM9Bnu3l5gZuYcpmmiebEn+fk7tHY8KirgXrPOWpKwZ+QFGts1Jl8c5uknHuO7b79nafEu7sAAge/R3/8Mp06ewjRTYe7qNWI/pWd0lOWmouO5UZbqEc0tRabr6Lkc733wPpe+vEixuMJvc9cJPJ8Tx09gbmxX+XvxHrt7B/jrxu88+cYYG0GKV0/wSz5JCl4QIWnG6alJDo6NUVwuYFsmC7cWMO/kVyiWNqjHGmFXF5ZqUot8/K2INtWi2lCgCZnoJIHH6Esvs7pSJIhC1tbWMZ0wobpZIosT3E6Hj8dfJ9YMklbKtlJ8+sNPlOIOIh6lI2yQ1lu00oicqRMYOqbruqhmkyAKCFshvbs6aAQBtJs0vIzNuIN1lSOOW3QFivTBBnqakGUaruui9+3ZTVd3J77vs1IocPHSV7TbDo16nSwFL3YIQ8EIfNpbTe7fvoljGDw7PMzI0BC6oet8dPYsnlKIpHxy/jxffD5L4PmE9Rp2s0qX2qI/rfDPrz9ixgotE6anPyRnW6C8mihVk6NHJ8Rus0Q3dDEtW9yhYRkbn5ADx06L+9q4OJ194pi2dFqmvDNxWBrKk2qUCUkaSCv2pbR5Xw4delNM0xDDMETXTbEsRyxTF1vXpPuRNum0DHn7rYNSLpXEbyWiEhGUtyNpGkoQNqVer8rs7GcyNLhfHMsW28qJZeiyy9LleXeffH3hguzUaqLCliRZJL7aEi1OA8myDA1ANLJU0DSN4soq+XyeUDSG3H0MuoOYThtRJuQMcKSJkTX4H3Ky8cRV8/WFAAAAAElFTkSuQmCC" alt="BMW" >

Przykład:

BMW

Dzięki takiemu rozwiązaniu nie trzeba wykonywać kolejnych zapytań HTTP do zewnętrznych zasobów. Wiąże się z tym jednak problem innej natury: obrazki tworzone w ten sposób nie będą buforowane przez przeglądarkę!

Przy pomocy tej metody można również tworzyć favicon i inne rodzaje grafiki. Najlepiej jednak nie przesadzać z tym sposobem :-) Więcej informacji w RFC 2397.

Złączenia plików JavaScript / CSS

Często programiści i webdeveloperzy dołączają do strony wiele różnych plików CSS i jeszcze więcej plików JavaScript. Powoduje to wykonanie niezliczonych ilości zapytań HTTP.

Przykład z życia wzięty (nasza-klasa.pl):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<link rel="stylesheet" type="text/css" href="http://0.static.nk-net.pl/style/main:1599">
<link rel="stylesheet" type="text/css" href="http://0.static.nk-net.pl/style/sledzik:71b0">
<link rel="stylesheet" type="text/css" href="http://0.static.nk-net.pl/style/popup:709d">
<link rel="stylesheet" type="text/css" href="http://1.static.nk-net.pl/style/home:ac98">
<link rel="stylesheet" type="text/css" href="http://1.static.nk-net.pl/style/blog/main_page:9ca2">
<link rel="stylesheet" type="text/css" href="http://0.static.nk-net.pl/style/allegro:4f78">
<link rel="stylesheet" type="text/css" href="http://1.static.nk-net.pl/style/szukaj:c814">
<link rel="stylesheet" type="text/css" href="http://1.static.nk-net.pl/style/ratings:5172">
<link rel="stylesheet" type="text/css" href="http://1.static.nk-net.pl/style/avatar:9e6e">
<link rel="stylesheet" type="text/css" href="http://1.static.nk-net.pl/style/gifts:0006">
<link rel="stylesheet" type="text/css" href="http://1.static.nk-net.pl/style/btab:d813">
<link rel="stylesheet" type="text/css" href="http://0.static.nk-net.pl/style/widgets/widgets:420c">
<link rel="stylesheet" type="text/css" href="http://0.static.nk-net.pl/style/quick_menu:58f9">

<script type="text/javascript" src="http://0.static.nk-net.pl/script/mootools:9d62" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/mootools-more:80e0" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/manual_login_stats:76a6" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/misc:635b" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/misc2:3c10" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/nk_window:8ac1" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/menu/menu:9e1f" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/swfobject:0168" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/tw-sack:f213" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/opacity:5328" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/are_friends:f6a0" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/avatar/avatar2:3d61" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/avatar/avatar_options:73d8" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/avatar/generic_avatar:ce3a" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/mail_invite:9caa" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/mootools_misc:107d" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/blog/normal_box:df91" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/blog/promo_box:4c33" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/popup:3810" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/ajax_form:aa5a" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/sledzik/sledzik_misc:9c46" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/main_logged_in:111b" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/last_photos:6da2" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/avatar/might_know_avatar:7cbe" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/might_know/might_know:2156" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/might_know/might_know_info_box:99be" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/paginator:1d76" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/sledzik/widgets/sledzik_widget_shout_sender:ab92" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/storage:23cb" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/sledzik/shout:c7a9" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/sledzik/sledzik_observer:a558" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/sledzik/sledzik_controller:73dd" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/sledzik/sledzik_shout_box:6d63" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/sledzik/sledzik_shout_stars:9dea" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/avatar/sledzik/sledzik_avatar_interface:dab6" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/avatar/sledzik/sledzik_followee_avatar:94d9" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/avatar/sledzik/sledzik_promoted_avatar:72f0" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/sledzik/sledzik_boxs:9488" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/sledzik/sledzik_box_initializer:d5f6" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/overlib:156c" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/events_controller:492b" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/nktalk/nktalk_watched_events:c9f6" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/tab_updater:c004" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/blinking_tab/blinking_tab:f50c" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/forum_school_tab:5595" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/widgets/widget:5ff3" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/widgets/widgets_box:f2d1" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/mails/mails_observer:4a9a" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/menu/quick_menu/quick_menu_modules:7ac7" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/menu/quick_menu/quick_menu:cc98" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/url_validator/url_validator:199d" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/url_validator/url_filters:0a64" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/url_validator/url_parser:55d1" charset="UTF-8"></script>
<script type="text/javascript" src="http://1.static.nk-net.pl/script/players/player_plugins:00b0" charset="UTF-8"></script>
<script type="text/javascript" src="http://0.static.nk-net.pl/script/players/player:f7d0" charset="UTF-8"></script>

Jak widzisz, sprawa nie wygląda za ciekawie. Niemniej jednak poważny webmaster nie dopuszcza do takich sytuacji, a szanuje swoich użytkowników i ich czas!

W celu optymalizacji strony należy ograniczyć liczbę pobieranych obiektów. W tym celu można połączyć wiele plików JavaScript / CSS w jeden duży (co później pozytywnie odbije się przy kompresji kodu po stronie serwera, o czym innym razem).

Across Domains

Metoda ta polega na tworzeniu wirtualnych serwerów dla domeny głównej, dzięki czemu możemy ominąć zasadę pobierania tylko dwóch plików jednocześnie! Bowiem tworząc nowe subdomeny dla wczytywanych obiektów nie ograniczamy się do jednej domeny, a dwóch lub więcej. Więcej na ten temat znajdziesz tutaj: Maximizing Parallel Downloads.

Przykład:

1
2
3
4
<script type="text/javascript" src="http://www.static1.adres-strony.pl/scripts/jquery.js"></script>
<script type="text/javascript" src="http://www.static2.adres-strony.pl/scripts/init.js"></script>
<script type="text/javascript" src="http://www.static1.adres-strony.pl/scripts/tabs.js"></script>
<script type="text/javascript" src="http://www.static2.adres-strony.pl/scripts/validate.js"></script>
Podsumowanie notki

Jak widać, minimalizacja zapytań HTTP nie jest trudnym zadaniem. Wystarczy niewielka ilość czasu, a średniej wielkości serwis możemy odciążyć o kilkadziesiąt % transferu. Moim zdaniem jest to bardzo opłacalne.

Za optymalizacją wydajności serwisów powinna przemawiać również korzyść ze strony wyszukiwarek, gdyż Google faworyzuje strony wczytujące się w krótszym czasie.

Także ze strony biznesowej musimy dążyć do optymalizacji serwisu. Z badań nad użytecznością serwisów wynika, iż użytkownik jest w stanie czekać do 5 sekund na rozpoczęcie wczytywania strony (Web Page Rendering Should Be Kept to No More than Four Seconds). Jeśli nie będzie widział większych postępów, opuści stronę i przejdzie do konkurencji.

Już wkrótce postaram się więcej napisać o optymalizacji serwisów internetowych (m. in. Content Delivery Network, Cache-Control Header, ETags, Gzip Components).

Komentarze (9)

  1. Michal Wachowski 5 kwietnia 2010

    Czyżby inspiracja bezowocną dyskusją na GL?

    Pominąłeś dość ciekawe zagadnienie, mianowicie – gdy pobierany jest JS, to nic więcej nie jest pobierane.
    (Może coś się zmieniło ostatnio, ale jakieś pół roku temu FF jeszcze tak robił, na innych przeglądarkach nie chciało mi się testować).

    A teraz do sedna – miały być praktyczne porady, kody, itp. a tu teoria.
    Jestem ciekaw jak to realizujesz (szczególnie łączenie i kompresję CSS/JS).

  2. Michal Wachowski 5 kwietnia 2010

    A – zapomniał bym – też chcę obrazek zamiast białego pampra ;)

  3. Kamil Brenk 5 kwietnia 2010

    Faktycznie, miało być dużo kodowania, a mało gadania. Ok, dziękuję za uwagę i motywację, w następnych postach będzie więcej kodu :-)

    Btw. obrazki do komentarzy są pobierane z serwisu gravatar.com – w ten sposób rozwiązuje to WordPress.

  4. Michal Wachowski 12 kwietnia 2010

    No to czekam z niecierpliwością na nowy wpis – tym razem z kodem :)

  5. Marta 1 lipca 2010

    Piszesz o tworzeniu subdomen w celu zwiększenia ilości plików możliwych do pobrania w tym samym czasie. Kiedy jednak bardziej skuteczne okazuje się trzymanie niektórych rodzajów plików na zupełnie innej domenie?

  6. Kamil Brenk 1 lipca 2010

    @Marta: podobne pytanie padło kilka dni temu na forum.php.pl – http://forum.php.pl/index.php?showtopic=153204 :-)

  7. Marta 1 lipca 2010

    Czytałam już temat na forum, ale skupiają się tam na różnych subdomenach w obrębie tej samej domeny, a mnie nie do końca o to chodzi.

  8. Kamil Brenk 1 lipca 2010

    Więc chodzi o Content delivery network? Technika ta polega właśnie na przechowywaniu danych statycznych na wielu zewnętrznych serwerach, w sposób duplikowany i bieżąco aktualizowany, zlokalizowany możliwie blisko użytkownika końcowego?

    Generalnie, chyba największą zaletą takiego rozwiązania jest możliwość przechowywania plików statycznych na serwerach z minimalną konfiguracją (przez co szybciej działających). Bez ładowania wszystkich modułów od proxy, przepisywania linków, wirtualnych hostów, autoryzacji, cache, deflate, itp itd.

    A czasem na zupełnie innym serwerze, o czym wspomniał erix we wspomnianym temacie na forum PHP.pl (nginx = static, apache = dynamic).

  9. Anna 10 lipca 2015

    Nie chcę się za bardzo wypowiadać o tym temacie bo dopiero uczę się HTMLa ale informacje na pewno mi się przydadzą bo również bardzo mnie denerwują wolno wczytujące się strony, zresztą na pewno każdego denerwują :) Pozdrawiam



Kamil Brenk Blog

PHP, JavaScript, SQL, HTML

  • Informacje o blogu

    Kamil Brenk

    Blog o tworzeniu aplikacji na potrzeby sieci Web.

    Praktyczne przykłady, porady i sztuczki. PHP, SQL, AJAX, JavaScript, HTML i pochodne.

    Kanał RSS

    • Najnowsze
    • Komentarze
    • Popularne
    • Liczniki w CSS
    • Wyprzedaż książek o programowaniu!
    • Niestandardowy placeholder
    • JavaScript w modułach
    • Co dalej z blogiem?
    • Interaktywna mapa w HTML i CSS
    • Olsztyn: Jak wyseparować zawartość zassaną przez file_get_content?
    • ERMLAB: Od czegoś trzeba zacząć :) Wiele osób właśnie stawia na...
    • david: co nalezy wkleić na stronę aby plik ze stylami był ladowany...
    • krynicz: Nie jestem pewien czy dobrze to rozumiem: wpisujemy OG w...
    • yaro: Jak zmienić re_write znak "_" na "-"?
    • Piotr: stworzyłem prostą stronkę w PHP, czy jest możliwość aby...
    • MichalR: Super sprawa... bardzo przydatne.. dzieki i pozdrawiam..
    • Niestandardowe czcionki na stronie
    • Sposoby wczytywania JavaScript
    • Gramatyka w PHP, część 1
    • Umowa i zaliczka dla freelancera
    • Wysyłanie wiadomości SMS w PHP
    • Projekt aplikacji po stronie klienta
    • Własny mechanizm Feed
  • Szukajka
    Wpisz co chcesz wyszukać na stronie…
  • Kategorie
    • Apache
    • Freelancer
    • Front-end Development
    • HTML5 & CSS3
    • Inne
    • JavaScript
    • Książki
    • PHP
    • Po godzinach
    • Pozycjonowanie
    • Protokół HTTP
    • SQL
    • Wyrażenia regularne
  • Moje serwisy
    • Testy zawodowe
    • Miłość, uczucia i seks
  • Czytane blogi
    • Wojciech Sznapka
    • Wojciech Soczyński
    • Michał Wachowski
    • Tomasz Kowalczyk
    • Filip Górczyński
  • Strona główna
  • Curriculum Vitae
  • O mnie
  • Przykład: Gramatyka w PHP
  • Przykład: Kompresja CSS
  • Przykład: Kompresja JavaScript
  • Przykład: Skracanie linków
  • Przykład: Wykrywanie serwera HTTP
  • Przykład: Własna bramka SMS
  • Mapa strony
  • Kontakt

Kamil Brenk © 2010. All rights reserved.

Designed by FTL Wordpress Themes brought to you by Smashing Magazine.

Do góry ∧