Pull to refresh

Объединение JS-файлов 2.0 (2/2)

Reading time3 min
Views997
Часть 1.

Итак, в конце прошлой части мы оставили нового пользователя наедине
со единственным JS-файлом, не включающем ничего лишнего. Стал ли при этом
пользователь счастливее? Ничуть. Наоборот, в среднем
пользователь1 стал более несчастным, чем раньше, а причина этому —
увеличившееся время загрузки страницы.



Приятная теория


вы находитесь на воздушном шаре!


Время загрузки ресурса через HTTP складывается из следующих основных элементов:
  1. время отсылки запроса на сервер T1 — для большинства2 запросов величина практически постоянная;
    время формирования ответа сервера — для статических ресурсов, которые мы сейчас и рассматриваем,
    пренебрежимо мало;
    время получения ответа сервера T2, в свою очередь состоящее из постоянной для сервера сетевой задержки L и
    времени получения ответа R, прямо пропорциональному размеру ресурса.


    В свою очередь, время загрузки страницы будет состоять из времени загруки HTML-кода и всех
    внешних ресурсов: изображений, CSS и JS файлов. Основная проблема в том, что
    CSS и JS-файлы грузятся последовательно3. В этом случае общение с сервером выглядит так:
    - запросили страницу
    - получили HTML 
    - запросили ресурс A: T1
    - получили ресурс A: L + R(A)
    - запросили ресурс B: T1
    - получили ресурс B: L + R(B)
    - запросили ресурс C: T1
    - получили ресурс C: L + R(C)
    

    Общие временные затраты при этом составят 3(T1+L) + R(A+B+C)

    Объединяя файлы, мы уменьшаем количество запросов на сервер:
    - запросили страницу
    - получили HTML 
    - запросили ресурс A+B+C: T1
    - получили ресурс A+B+C: L + R(A + B + C)
    

    Очевидна экономия в 2(T1 + L).
    Для 20ти ресурсов эта экономия составит уже 19(T1 + L). Если взять достаточно типовые сейчас для
    домашнего / офисного интернета значения скорости в 256 кбит/с и пинга ~20–30 мс, получим экономию
    в 950 мс — одну секунду загрузки страницы. У людей же, пользующихся мобильным или
    спутниковым интернетом с пингом более 300 мс, разницы времён загрузки страниц составит
    6–7 секунд.

    На первый взгляд, теория говорит, что загрузка страниц должна стать быстрее. В чём же она разошлась
    с практикой?

    Суровая реальность


    Хотели как лучше, а получилось как всегда.


    Пусть у нашего сайта есть три страницы P1, P2 и P3, поочерёдно запрашиваемые новым пользователем.
    P1 использует ресурсы A, B и C, P2 — A, С и D, а P3 — A, С, E и F.
    Если ресурсы не объединять, получаем следующее:
    • P1 — тратим время на загрузку A, B и C
    • P2 — тратим время на загрузку только D
    • P3 — тратим время на загрузку E и F


    Если мы слили воедино абсолютно все
    JS-модули сайта, получаем:
    • P1 — тратим время на загрузку (A+B+C+D+E+F)
    • P2 — внешние ресурсы не требуются
    • P3 — внешние ресурсы не требуются

    Результатом становится увеличение времени загрузки самой первой страницы,
    на которую попадает пользователь. При типовых значениях скорости/пинка мы начинаем прогрывать уже
    при дополнительном объеме загрузки в 2–3 килобайта.

    Если мы объединили только модули, необходимые для текущей страницы, получаем следующее:
    • P1 — тратим время на загрузку (A+B+C)
    • P2 — тратим время на загрузку (A+C+D)
    • P3 — тратим время на загрузку (A+С+E+F)

    Каждая отдельно взятая страница при пустом кеше будет загружаться быстрее, но все они вместе —
    медленнее, чем в исходном случае.

    Получаем, что слепое использование модного сейчас объединения ресурсов часто только ухудшает
    жизнь пользователя
    .

    Решение


    — можно ли проглотить бильярдный шар?
    — можно, но, как правило, не нужно.


    Конечно же, выход из сложившегося положения есть4. В большинстве случаев
    для получения реального выигрыша достаточно выделить «ядро» — набор модулей, используемых на всех
    (или по крайней мере на часто загружаемых) страницах сайта. Например, в нашем примере достаточно выделить
    в ядро ресурсы A и B, чтобы получить преимущество:
    • P1 — тратим время на загрузку (A + B) и C
    • P2 — тратим время на загрузку D
    • P3 — тратим время на загрузку (E + F)

    Вдумчивый читатель сейчас возмутится и спросит: «А что, если ядра нет? Или ядро получается слишком
    маленьким?». Спешу заверить — это легко5 решается вручную выделением 2–3 независимых
    групп со своими собственными ядрами. При желании задачу разбиения можно формализовать и
    получить точное машинное решение — но это обычно не нужно; руководствуясь простейшим правилом — чем
    больше ядро, тем лучше, можно добиться вполне приличного результата.

    Как говорят на Хабре: «Каков же месседж этой статьи?» Ограничимся жалкими тремя пунктами:
    • бездумное следование модным веяниям приведёт к бесполезной работе;
    • модные веяние часто несут в себе неплохие идеи;
    • если вы любите своих пользователей — объединяйте ресурсы с умом.


    1 с пустым кэшем, конечно.
    2 подразумевается, что большая часть запросов — это GET-запросы с разумной длиной URL.
    Длина такого запроса примерно постоянна, и составляет ~450–600 байт.
    3 по крайней мере, пока они находятся на одном хосте.
    4 и, что приятно видеть из комментов, используется.
    5 «У нас есть такие приборы — но мы вам про них не расскажем». Придётся поверить на слово.
Tags:
Hubs:
+16
Comments10

Articles

Change theme settings