• Strona główna
  • Curriculum Vitae
  • O mnie
  • Mapa strony
  • Kontakt
Niebieski Pomarańczowy Zielony Różowy Fioletowy

Minimalizacja zapytań HTTP

Opublikowane 4 kwietnia 2010. Autor: Kamil Brenk. Wizyt: 151.

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

kwi 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 (8)

  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).



Dodaj komentarz

XHTML: Możesz użyć następujących tagów
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code lang="" escaped=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

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
    • Konwersja JS i CSS do PNG
    • Optymalizacja wyrażeń regularnych
    • Cross-Domain JavaScript
    • Kompendium programisty #1
    • Jak pobierać zewnętrzne zasoby?
    • 960 Grid System
    • Kamil Brenk: @eN: Nie sposób się nie zgodzić z tym co piszesz, masz...
    • Michal Wachowski: To jest na prawdę szalone :D
    • The one: Zarąbista gierka :D
    • eN.: Problem w tym że nie zwracają tego samego, a dokładniej1...
    • Michal Wachowski: DAS - deterministyczne automaty skończone, AS - to samo ale bez...
    • Kamil Brenk: DAS / AS? Pierwsze słyszę :-) Raczej nie będę już miał...
    • Michal Wachowski: Jak na studiach będziesz mieć AS i DAS to wiele się wyjaśni...
    • Gramatyka w PHP, część 1
    • Projekt aplikacji po stronie klienta
    • Optymalizacja wyrażeń regularnych
    • Yii PHP Framework vs Symphony
    • Minimalizacja zapytań HTTP
    • Jak pobierać zewnętrzne zasoby?
    • Usługi sieciowe w PHP: REST
  • Szukajka
    Wpisz co chcesz wyszukać na stronie…
  • Kategorie
    • Apache
    • Front-end Development
    • HTML5 & CSS3
    • Inne
    • JavaScript
    • PHP
    • Po godzinach
    • Protokół HTTP
    • SQL
    • Wyrażenia regularne
  • Moje serwisy
    • Testy zawodowe
    • Miłość, uczucia i seks
  • Czytane blogi
    • Wojciech Sznapka
    • Wojciech Soczyński
    • Dzienniki zyxowe
    • Przemysław "eRIZ" Pawliczuk
  • Archiwum
    • sierpień 2010
    • lipiec 2010
    • czerwiec 2010
    • maj 2010
    • kwiecień 2010
    • marzec 2010
    • luty 2010
    • styczeń 2010
  • Strona główna
  • Curriculum Vitae
  • O mnie
  • Mapa strony
  • Kontakt

Kamil Brenk © 2010. All rights reserved.

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

Do góry ∧