Pull to refresh

Comments 87

Когда уже в России будет неактульная вся эта оптимизация Kb страницы? Или у вас все еще dial up существует? Сертезно, это не наезд, просто интересно…

У меня например как и у большинства тут дома 5Mb линия и 7Mb линия на wireless internet на лэптопе от сотового провайдера…

Проблема с трафиком от провайдеров отпадает тоже — неограниченный везде.

Единственный + вижу в этом это типа на один запрос меньше к серверу что бы не запрашивать файл… но заморачиваться ради этого?

З.Ы
Могу быть не прав… объясните…
1. за МКАДом анлими только набирают популярность, а скорости выше мегабита не такая заурядная вещь.
2. экономия килобайт важна на мобильных устройствах, работающих через сотовые сети. Я, например, сёрфя с мобильника через 3G вполне ощущаю разницу в весе страницы в 10кб.
3. Копейка рубль бережёт.
4. Если всё аккуратно и красиво экономит пусть и копейки — это здорово.

Вы не задумывались, почему до сих пор существует демосцена? Это из той же оперы. Давно можно все ресурсы хранить в распакованном виде, писать на языках высокого уровня — производительность позволяет, места в памяти достаточно. Однако ж находятся чудаки, которые пишут игры, умещающиеся в 64кб в одном бинарном файле. Как думаете, почему?
Данные по памяти: увеличение времени загрузки главной страницы гугл на 20% (~4ms) уменьшили доход от adsens на 30%.
Ну вот как видишь по скриншоту, оптимизация нужна.
А траффик режется проксёй на работе. Эта одна из причин из множества.

В любом случае, без доп. запросов даже на супер-быстром интернете, страница покажется быстрее.
Потому что по большому счёту запрос — Not Modified — отработает что у тебя, что у меня одинаково.

Но главный плюс этого способа — отсутствие проблем с кэшем. Браузер не всегда отсылает запрос на изменение файла. Даже посмотри на моём скрине, при втором запросе он не проверил ни одной картинки! А откуда он знает, что ни одна не изменилась! Тоже самое было со скриптами, пока я не открыл этот способ.

Было очень тяжело объяснять заказчику «Не работает?.. А нажмите Ctrl-F5.».
Думаю, по промежутку времени между запросами к тому же ресурсу браузер строит стратегию «тратить/не тратить» время на «запрос на изменение»… хтмл, он то конечно проверяет на изменения, а вот те же включаемые внешние файлы — не факт.

мне думается, что это логично…
Встречался как с проблемой кеширования, так и с проблемой кеша проксей/браузера, работая над крупным проектом. Платформа была PHP, так что и решение было другим. Решил её достаточно прозрачным способом: для уменьшения запросов объединял все внешние js-файлы в один в папку cache и придавал этому файлу md5([имяфайла1+timemodified1]+[имяфайла2+timemodified2]+...).

Вы правы, изменение одного файла/модуля обновит весь «пакет» файлов, но часто ли это бывают изменения в js, когда проект не в стадии постоянной разработки? В итоге, выигрыш пусть и в десятках миллисекунд, но и они в сумме играют решающую роль как при нагрузке сервера, так и при скорости отдачи страницы.

Итогом этого решения было:
— один запрос на весь файл (его спец.скриптами или иными способами можно сжать хоть в gz)
— даже когда кеш браузера работает работает бредово (особенно оперы, уж извините, поклонники), но с новым именем всегда подтягивает — как Вы и заметили
В случае PHP я просто проходился по конечному HTML, который вынимал их из буфера (функции ob_..) и проверял все включённые скрипты. Конечные серверные потери на такую операцию занимали десятитысячные секунды, в то время, как при отдаче отдельных файлов потери были до 0.8 секунды. (проверка на канале 100Мб).

Скрипов было на каждой из страниц порядка 15 (страницы были блоковые и каждый блок тянул для себя отдельные стили и скрипты).
Тогда встаёт другая проблема.
Зачем мне скрипты на страницы, которые на ней не используются.

Я имею ввиду, если запихивать все скрипты в один пакет, тогда зачем мне там код TabControl'а, которого на странице нет.

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

В моём случае, пока он пройдёт по главной и логину, основные скрипты будут скачаны, а дальше по 2-3 специфичных для отдельных страниц.
Нет-нет. В том случае, который описал я, это не так:

Страница содержит набор блоков, каждый блок свой файл стилей и файл js. Таким образом, не смотря на то, что это пакет, он содержит только актуальные для данной страницы скрипты.

Я за то, чтобы объединять файлы, которые используются на большинстве разделов. Вы же сами упоминали, что 1 файл по 100Кб загружается быстрее, чем 10 по 10Кб (особенно, если с одного домена). В этом случае проблему трафика прекрасно решает кеширование браузером, а скорость загрузки страницы хорошо возрастает.
а зачем привязка ко времени изменения файла? можно же просто взять md5 от получившегося файла и пихнуть после?
<script src=«full.js?<?=md5('full.js');?>»>
как только меняется любой компонент full.js — меняется md5
А почему это проще? Цель та же, выполнение >> быстрее.
я про скорость не говорил…
но чем копаться с циклами перебирать все файлы, вычислять их время изменения и т д и тп, по-моему проще взять md5 от их общего содержимого
Цикл перебиратеся только однажды при загрузке приложения. И сохраняется инфа о модификациях в локальной переменной.

И то это сделано для того, чтобы каждый раз не дёргать жёсткий диск для выяснения о модификации файла.

А вы предложили то же самое, только медленнее.

Вам также надо каждый раз считать md5, или однажды просчитать его «копанием в цикле», что куда выгоднее.

А монитор сделан для того, чтобы если вдруг понадобится изменить скриптовый файл, не перегружать для этого приложение.
просто я считаю md5 от того, что отдаю пользователю а не от ненужных пользователю дат
Мы наверное говорим о разных вещах.

Если пользователю не нужны мои даты, зачем ему твои md5?
Думаете правильно с точки зрения оптмизации, но с точки зрения ресурсов — нет.

Для того, чтобы составить md5([имяфайла1+timemodified1]+[имяфайла2+timemodified2]+...) нужно:
1. Пройтись циклом по всем файлам и считать дату изменения (процесс быстрый, поскольку ОС или язык может кешировать подобные данные)
2. Создать md5() от короткого стринга.

Для создания md(content_file1+ content_file2+...) нужно:
1. Пройтись циклом по всем файлам и прочитать их содержимое в локальную переменную
2. Создать md5() от длинного стринга

В итоге, во втором случае, мы имеем бездарную трату ресурсов на чтение содержимого файлов, увеличение памяти текущего скрипта на объём переменной с содержимым файлов скриптов и увеличение нагрузки на расчёт md5() относительно «короткого» стринга. И если помножить эту операцию на количество генераций каждой страницы, то получается весьма весомая цифра.

И это в то время, когда и первый, и второй способы приводят к одинаковым результатам.
с точки зрения оптимизации = с точки зрения логической оптимизации
«неактульная вся эта оптимизация Kb страницы»
Эта проблема будет актуально долго. Ведь на нее можно смотреть и с точки зрения хоста, а точнее платы за хостинг и трафик. Что для вас 1КБ для них выливается в терабайты, лишней и никому ненужной информации, которую можно не передавать добавив пару строчек в код. Ну кто от такой халявы откажется? Гляньте на Гугл, Яндекс, Яхуу — это пример того, что такая проблема весьма интересна с другой точки зрения.
Оптимизация нужна всегда.

«как и у большинства тут» тут, это где?

Если немного пройти за МКАД, интернета будет существенно меньше. А если за пределы Московской области, интернета будет совсем мало.

У меня, к примеру, мобильный edge c пингом 700ms, и оптимизированная страница чувствуется. К тому же трафик ограничен — всего 1,1 ГБ в месяц. Живу в новом, охраняемом высотном доме, но кроме edge, интернета нет вообще никакого.

-1
Вообще не понимаю почему лепите минусы?
Почему минусуете коммент AlexSpaizNet? Он же вначале предупреждает, что не наезжает и просит объяснить, если не прав.

И мне в карму кто-то подкинул гадость не объяснив?
Неужели статья не достойна тематического блога Web-разработка или Оптимизация?

Вообще главное в минус меня не опустите, чтобы я мог что-то ещё полезное написать…
не обращайте внимания на злыдней: обычно им сказать-то и нечего
Хорошая статья. Правда много написано вокруг одной главной изюминки :)
статья хорошая, но, имхо, ничего нового. В YASS та же самая <a href=«webo.in/articles/habrahabr/79-coupling-async-modules/>модульная загрузка скриптов реализована на более „высоком“ уровне — можно дерево лепить и апдейтить любой блок по загрузке как корня ветки, так и отдельных модулей. И само дерево можно „на ходу“ выстраивать. И загрузка дерева идет по DOMContentLoaded, а не в head страницы.

Да, там нет кэширования. Но оно автоматически появится, если задать параметр в имени модуля — YASS-то гораздо более гибкий, чем описанный подход.
Не все пользуются YASS.
А вот модифицировать имя загружаемого скрипта под силу каждому.
Хотя бы проставить *.js?v=32432454
Мне кажется красивее будет подключать файл примерно так:
js/javascript.js?633675510761
В фаербуге имя фала будет более читабельным :)
локальные прокси могут не кэшировать. Т.е. в общем случае вариант с заменой физического файла более предпочтительный
Да, я в концовке заметил, что можно поступить как вы предложили.
Но я не уверен что будет с кэшем.
А поскольку HttpHandler я использую в любом случае, моё наменование для меня надежнее.
У вас водичка попала на некоторые скриншотики. размылись буковки, немножко. :-)
Думаю из-за того, что в стилях хабра стоит такое:
.hentry .content img { max-width:100%; }

Предполагаю, чтоб страница не вылетала за края браузера.
Может виноват вечер пятницы, но по-моему, всё это можно описать в меньшем количестве строчек кода… Мне кажется всё слишком «растянуто» для такой не самой сложной фишки… Хотя «для начинающих» очень даже хорошо разжевано =)
Написано ещё вчера для песочницы. И только к вечеру добралось до тематического блога.

Решение для меньшего количества строк предложено в концовке.

А так я раскрыл тему изюминки, обработчика JS-файла и монитора файловой системы.
Спасибо за статью, не далее как вчера возникла необходимость объяснять заказчику про ctrl+f5 :)
Наверное в скором времени внедрим для своих проектов подобное решение.
Пожалуйста.
Я очень рад что кому-то пригодилось.
Ещё более разумным мне видится проставлять не дату модификации файла, а его версию в SVN, к примеру. Заодно появляется возможность не только увеличить скорость загрузки страницы у юзверя, но и увеличить пропускную способность сервера.
Я наверное не понимаю, что вы предлагаете.
1) как из серверного кода я узнаю версию SVN (хотя это моя проблема)
2) какой выигрыш это даст? можно проставлять любой идентификатор времени изменения файла.
UFO just landed and posted this here
Я уже ответил выше, что при таком подходе мы грузим скрипты на страницу, где они не нужны.
Получается, чтобы загрузить первую страницу, он будет грузить скрипты для остальных страниц.
Может не дождаться и уйти. Тогда смысл в оптимизации.

Согласен в том, что это для сайтов-визиток из 1-2 страниц, но тогда и какие там могут быть сложные скрипты?
UFO just landed and posted this here
Не понимаю зачем делать другое имя файла, ведь можно просто добавить параметр Scripts/core.js?633675510761. Смысл тот же, а телодвижений приходится делать меньше.
Я правда добавляю не время, а номер ревизии или номер выпускаемой версии.

Чтобы это работало написан небольшой скрипт на php, который проходит по всем шаблонам и там делает нужные подстановки.
Номер ревизии применяется ко всем файлам, даже тем, которые не изменились?

Не понимаю зачем делать другое имя файла, ведь можно просто добавить параметр Scripts/core.js?633675510761.

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

Чтобы это работало написан небольшой скрипт на php, который проходит по всем шаблонам и там делает нужные подстановки.

Не знаком с PHP. Возможно, там это действительно решается гораздо проще, только я редко вижу такое решение.

В любом случае, спасибо за комментарий.
Какой-то ппц пятничный.
Всё описанное реализуется одной строкой кода в каком-нить акселераторе типа 0w или nginx'а и использованием нормального шаблонизатора.
Будет интересно увидеть эту строчку кода.
Цитата из документации 0w:

В поле local_path можно использовать спец-символ `$', в этом случае для всех запросов данного Alias'а будет использован именно указанный local_path

Пример:
на любой запрос иконки отдавать одну и ту же иконку:
Alias /*/favicon.ico /home/site/web/favicon.ico$


Спасибо.
Вообщем, действительно, handler можно выкидывать. Хотя я до этого использовал его с целью проверки прав на доступ. А тут он просто мне пригодился.
и что такого увидит сторонний пользователь, если скачает твои суперсекретные скрипты? имена? явки? пароли?
По большому счёту ничего. Но с другой стороны нечего ему знать админское API, мало ли где-то вход забыл заварить.

А вообще это пошло с одного сайта, не буду называть его вслух. Через админку он мог увидеть, что на сайте работают боты и им бы это крайне не понравилось.
Но ведь всё равно нужно сформировать то, что будет стоять за этим спец-символом $.
Эээ? В указанном подходе Вам будет достаточно менять то, что находится вместо звездочки.
Увеличивайте ручками на единицу и не заморачивайтесь.
При наличии нормального шаблонизатора это делается ровно в одном месте и занимает порядка 3 секунд.
Да, но что мне ставить вместо звёздочки? Что увеличивать на единицу?

Вместо звёздочки, я использую дату модификации.
Что угодно.
Можете писать в шаблонах хоть /css/001/style.css, хоть /js002/button.js
Я вас уже давно понял и сказал спасибо.
Теперь поймите меня что мне не просто надо писать 001 и 002
мне нужно писать информацию о содержимом и изменении этого содержимого

в статье я предлагаю писать время модификации

хотя я понимаю метод не мой, это не я предлагаю, это уже давно придумано и используется
я лишь написал об этои на хабре
Изменение счетчика — это тоже информация об изменении содержимого.
Достигается ровно то же самое, что предложили Вы, но без излишнего кода.
Кто изменяет счётчик и формирует имя?
Может приведёте ещё строчку кода?
номер ревизии из cvs/hg ;)
А смысл? Подключение таким образом скрипта всё равно, как правило, из другого файла. А для него и счетчик сойдет.

Тем более, что в этом файле наверняка подключается несколько разных скриптов/файлов стилей, так что для каждого будет свой номер.

Вот пример с одного из моих проектов:
/>
<script type="text/javascript" src="/js102/common.js"></script>
<script type="text/javascript" src="/js112/context_help.js"></script>
<script type="text/javascript" src="/js116/complaint_script.js"></script>
<script type="text/javascript" src="/js034/plugin_fly.js"></script>
Так вы ручками прописываете счётчик?
Так если у меня проект 20 файлов, я должен в каждом прописать /js103/common.js
Я правильно понимаю?
Эээ… Я же писал
При наличии нормального шаблонизатора это делается ровно в одном месте и занимает порядка 3 секунд.
В крайнем случае, замена счетчика в N файлах — одна строка на bash с использованием find + grep + sed + awk
Альтернативный подход:
В html-шаблоне пишется шаблонный тэг, описывающий набор файлов, нужных для страницы.

Если debug-режим включен, тэг разворачивается в html-тэги «script src» для каждого из нужных скриптов, в итоге скрипты грузятся по одному, то есть никакой обработки скриптов не происходит.

Если debug-режим выключен, скрипты комбинируются в один файл с учётом зависимостей, при этом сами зависимости вырезаются регулярными выражениями, опционально результат сжимается обфускатором для уменьшения объёма. Имя файла результата зависит от набора входных файлов и времён модификации файлов в директории со скриптами, таким образом браузер получает страницу с script src=X.js, где X меняется только тогда, когда изменились либо сами файлы, либо набор их использования в html-шаблоне. Чтобы не считать хэш-функцию от метаданных используемых скриптов на каждую загрузку страницы используется либо кэширование результата на несколько секунд, либо обновление кэша вручную в скрипте обновления рабочей копии.
Как реализована индикация процесса загрузки — мне неизвестно, поинтересуюсь у автора при случае.
Метод суровый, но у нас вариантов не густо — либо грузить пользователю пару мегабайт одним файлом, либо несколько сотен мелких.
время загрузки первой страницы… 5 минут 0_0 редко кто сможет выдержать столько времени…
Страница не главная, а из админки. Специально выбрал с кучей скриптов.
Сама страница HTML 33Кб, грузилась 255мс.
А вообще это очень топорный интернет, как видишь там всего 365Кб в сумме (вместе с графикой).

Но даже с ним при втором заходе выдал за 7с.

А вообще такой интернет, позволяет писать быстрые приложения, потому что для себя стараешься ;-)
и что с того? я сдохну ждать появление такой админки.
Почему ты сдохнешь?
365Кб страницы для тебя много?
7 секунд для меня — много.
Если у тебя интернет 5Кб/c, то у тебя нету выбора.

А вообще я сейчас внимательно посмотрел картинку, страница загрузилась за 405 мс, а потом пока я делал скрин, прошло два запроса, данные подтянуло, ещё что там было, и 7 секунд — это результат 3 запросов с перерывом между ними.
выбор у меня есть — не использовать поделки криворучек, которые не способны самостоятельно собрать весь мусор в один пакет, а не кормить меня обещаниями вида «вот ещё чуть-чуть и наконец всё прокешируется и страница будет отдаваться не 30 секунд а всего 5».
Так что ты делаешь на хабре, где даже на этой странице я насчитал 12 файлов?
я тут ничего не делаю. боже упаси =)
Наверное, каждый веб-программист должен «открыть» для себя управление кэшированием через имя в урле… Правда, я впервые вижу, чтобы это открытие вызывало у автора столько радости и плясок вокруг. Могу только позавидовать:)

Подскажу ещё открытие на эту тему: не менять физическое (на диске) имя файла, а менять только путь к нему в коде. Делать преобразование script.v123456789.js => script.js при помощи mod_rewrite, или кто там у вас сервером работает. Тогда и скартинками проблем не будет, и вообще ни с чем.
За подсказку спасибо. Но, если быть внимательнее, физическое имя файла я не меняю.
Имя я формирую при рендинге, а дату модификации (чтобы получить оригинальный файл), отсекаю в хэндлере.

Единственное, хэндлер можно выкинуть, и отсечение делать просто через url rewrite, если он не выполняет других функций.
Но всё равно остаётся часть с получением уникального идентификатора файла.
про доказано «От сжатия я также отказался, т.к. доказано выйгрыш в скорости загрузки файла теряется в скорости его распаковки» можно привести источники? И, кстати, подправьте «выйгрыш»
Поддерживаю. Совершенно непонятно когда и кто успел это доказать.

На мегабите сжатая страница весьма грузится ощутимо быстрее, чем несжатая. Также не стоит забывать, что при сжатии на уровне 1-4 мы в большинстве случаев экономи ресурсы нашего сервера (быстрее отдали страницу — быстрее освободили память).

Конкретная сравнительная статистика есть на webo.in.
Соглашусь. Тут я смело заявил. Поправил своё высказывание.
У меня возникала ситуация, когда распаковка 100Кб js файла под ослом, запакованного пакером Dean Edwards'а (проверял со сжатием Base62 и без), периодически вызывало подвисание шестого осла. Пришлось отказаться.

Из-за чего это происходило выяснить мне не удалось.
Видимо поэтому в nginx есть настройка:
syntax: gzip_disable regex [regex ...]
default: нет
context: http, server, location

Директива (0.6.23) запрещает сжатие ответа методом gzip для запросов со строками «User-Agent», совпадающими с заданными регулярными выражениями.

Специальная маска «msie6» (0.7.12) соответствует регулярному выражению «MSIE [4-6]\.», но работает быстрее.
1.
идея хорошая, но баянная и сто раз написанная.

поищите готовые библиотеки.

2. есть два варианта и они в постоянной войне друг с другом —
а) делать один файл б)не делать

всё зависит от проекта.

и от стоимости на оптимизацию.

потому что подтачивать проект можно вечно. вот только вопрос — будет ли это выгодно инвестору?

если проект такой, что на почти всех страницах используется весь код — то нужно делать один файл, потому что даже если на каком-либо проценте страниц будет использоваться малюсенький кусочек скрипта в 2 кбайта, например, то нет смысла его размещать в отдельном файле — выгоды нет.

если же проект многоплановый и разносторонний,, например, на отдельной одной странице может использоваться скрипт в >50 кб и он больше нигде не будет и таких страниц может быть десятки, то имеет смысл подгружать этот файл отдельно. другой же код, который используется равномерно на большинстве страниц, нужно объединять в один — это выгоднее.

3. есть ещё третий вариант — грузить нужные скрипты по запросу действия. самый оптимальный вариант, считаю. например, на странице может быть действие — «экспорт чего-то» или импорт. и эта кнопка почти не используется. очень редко. поэтому лучше все файлы для тех действий, которые будут после нажатия на эту кнопку, грузить только после нажатия оной кнопы. нет смысла грузить скрипты для данной кнопки при загрузке станицы.

=====

успехов всем нам (-:

Согласен со всем. Дополню только проблему третьего варианта: если при подзагрузке скрипта произошёл сбой связи (на секунду пинг пропал или еще куча других вариантов, что случается по множеству причин, независящих от хостера), то пользователь может не сообразить почему «в программе даже about не работает».
ну так сделать TimeOut и повторять загрузку несложно (-|
Информация к размышлению по поводу Expires на несколько лет вперед.
Анализировал логи одного магзина и выходило так что раз-два в сутки почти все подгружают контент который по идее должен навсегда закешироваться. Тоесть кеш банально перетирается другими сайтами если пользователь активно по ним ходит. Из этого вывод а есть ли смысл? Можно ставить кеш на сутки при этом не потерять в экономии трафика и не замарачиваться с обновлением.
Сам не пробовал, просто мысли :)
1. Пользователь не в курсе, что такое Ctrl + F5. Об этом в курсе продвинутый пользователь, коих процентов 5. Следовательно проблема может возникнуть банальная — будут сыпаться ошибки у пользователя и он огорчится.

2. Решение вроде интересное, но какое-то однобокое и огромное (не изящное), хотя если работает, то и хорошо. Я бы хотел увидеть его более элегантным и минимум на двух серверах. На IIS`ах меньше людей сидит, нежели на тех же Apache`ах под PHP и проч.
К сожалению, я могу предложить только ASP.NET+IIS.

Главное я озвучил теорию, а прикрутить к своим проектам — это уже ваша задача как, элегантно и на чём.
2. Да это уже больше не к Вам, а к другим людям, которые могут заоптимизировать и украсить.
Уменьшите скрины со сглаживанием, смотреть на картинки невозможно!
А вообще, по делу, всегда использовал code.js?version=12345 и никаких проблем не было.
Я сижу по Хромом и не видел, что такие проблемы со скринами.
Немного ужал по ширине, вдвинув временные интервалы. Должно стать лучше.
Спасибо, стало намного лучше!
P.S. Хром наверное ресайзит картинки со сглаживанием.
Хороший материал. Спасибо, что ещё раз обратили внимание на проблему кеширования javascript.
Sign up to leave a comment.

Articles