Кэширование js сжатием gzip

    Cache — временные данные или устройство по их хранению, созданные для ускорения чтения/записи. Все программисты это знают. Ускорение загрузки web-сайтов тема обширная, начинающаяся с сервера и заканчивающаяся клиентом. К сожалению я не нашёл более-менее подходящих решений по объединению и кэшированию js-кода, поэтому к своему блогу я написал свою схему, о которой вкратце и расскажу..
    Существует сжатие «packer», которое убирает все символы форматирования и переименовывает имена функций и переменных в js и предоставляет т.н. minified-версию скрипта. Все с этим прекрасно знакомы на примере больших библиотек jQuery, TinyMCE, prototype. Кроме того что код становится совершенно не читаемым, это может вызвать неработоспособность кода, когда имена переменных динамические.
    Моя идея простая — разделять js/css по файлам разработчикам надо для поддержания модульной структуры. Обычно я в контроллере создаю список файлов которые надо присоединить к данному документу, вместо того что-бы прописывать это вручную в темплейте. Но теперь надо сделать так, что-бы до показа темплейта вызывалась функция кэширования, которая проходилась бы по списку, проверяла из них локальные файлы на время изменения, объединяла в один файл и создавала или перезаписывала gz-файл с именем, сформированным из md5-хэша имён входящих файлов.
    Всё просто и в сумме заняло часа 4 на раздумье. Привожу метод cache_js из класса Controller.

        function cache_js(){
            $arrNewJS=array();
            $strHash='';
            $strGzipContent='';
            $intLastModified=0;
    
            //проходимся по списку файлов
            foreach ((array)$this->scripts as $file){
                if (substr($file,0,5)=='http') continue;
                if ($file[0]=='/') $strFilename=sys_root.$file;
                else $strFilename=sys_root.'app/front/view/'.$file;
                $strHash.=$file;
    
                //читаем содержимое в одну строку
                $strGzipContent.=file_get_contents($strFilename);
                $intLastModified=$intLastModified<filemtime($strFilename) ?  filemtime($strFilename) : $intLastModified;
            }
            $strGzipHash=md5($strHash);
            $strGzipFile=sys_root.'app/front/view/js/bin/'.$strGzipHash.'.gz';
    
            //проверяем надо ли перезаписать gz-файл
            if (file_exists($strGzipFile) && $intLastModified>filemtime($strGzipFile) || !file_exists($strGzipFile)){
                if (!file_exists($strGzipFile)) touch($strGzipFile);
    
                //используем функции встроенной в php библиотеки zlib для архивации
                $gz = gzopen($strGzipFile,'w9');
                gzputs ($gz, $strGzipContent);
                gzclose($gz);
            }
    
            //перезаписываем список на один файл
            $arrNewJS[]='js/bin/'.$strGzipHash.'.gz';
            $this->scripts=$arrNewJS;
        }

    Про css я писать не стану, идея аналогичная. Единственный вопрос в автоматизации кэширования и в порядке входящих файлов. Впрочем в результате сжатия 5 запросов превратилось в 1, а суммарный размер уменьшился в 3 раза.
    Читайте так-же



    Оригинал

    Средняя зарплата в IT

    120 000 ₽/мес.
    Средняя зарплата по всем IT-специализациям на основании 7 204 анкет, за 1-ое пол. 2021 года Узнать свою зарплату
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

    Комментарии 29

      +1
      а давайте ваш код спрячем под хабракат? :)
        +1
        ребята, вы помоему сильно всё усложняете...

        используйте обычный mod_rewrite:


        SetOutputFilter DEFLATE



        "да будет свет!" :-)
          0
          объединять файлы в один всё-равно надо
            0
            в большинстве случаев это зависит от размера.
            заметил что плохо себя ведут файлы больше чем 50кб.
              0
              Согласен, надо придерживаться золотой середины - маленькие убивают своей многочисленностью, большие слишком долго грузятся. Верхняя планка с ростом пропускной способности канала будет понемного повышаться, а вот нижняя - наврядли, хотя я мало знаком со статистикой улучшения пакетной производительности рутеры в WAN-сетках.
          0
          ребята, не усложняйте...

          используйте обычный mod_rewrite:
          <IfModule mod_deflate.c>
          <FilesMatch "\.(js|css|html|php)$">
          SetOutputFilter DEFLATE
          </FilesMatch>
          </IfModule>
          </code>

          "да будет свет!" :-)
          0
          можно попросить перенести в Клиентскую оптимизацию? Я бы выложил еще и на webo.in, только решение хорошо бы отформатировать и прокомментировать построчно (например, подразумевается наличие gzlib — или как ее?)
            0
            Отформатировал и прокомментировал. Переносить в другие блоги не научился. Можно и на webo.in выложить если сошлётесь :)
              0
              для переноса в другой блог нужно в него вступить, а затем в редактировании статьи выбрать его из выпадающего списка

              заметил еще, что https:// не проверяется в адресе файла
                0
                исправил (думаю мало кто называет файлы с http..) и перенёс
            0
            > $intLastModified=$intLastModifiedfilemtime($strGzipFile) || !file_exists($strGzipFile)){

            Помоему у вас тут в коде какаято ошибка.
              0
              Это тоже валидатор порезал.. смотрите оригинал, там < filemtime($strFilename) ?
                0
                ссылки на оригинал нет
                  0
                  Исправил. Валидатор — жесть, кавычек одинарных тоже не понимает.
              0
              ссылку http://xn--javasrit-cchh.ru/optimize/cac… НЛО поломало?
                0
                да, это javascript.ru почему-то ломается
                0
                Да, я где-то делал такое. Правда, за одним исключением — имя результирующего файла был не хешем, а UnixTimestamp-ом для обеспечения корректной загрузки клиентами обновленной версии стилей/скриптов в случае применения агрессивного кеширования средствами web-сервера, а также при работе через агрессивно кеширующий прокси.
                  –1
                  Господа, один вопрос. Где-то я слышал, что gzip-нутый контент не кешируется ни проксями ни браузерами.
                  Неспроста ведь в настройках gzip для Tomcat стоит exclude для .css и .js. То есть при каждом посещении страницы все стили и скрипты грузятся по новой. Так что...
                    0
                    кто-то где-то слышал... Некоторые прокси, действительно, так делают. Проблема сложная и малоисследованная, скорее всего, должно помогать Cache-Control: private
                    +1
                    Все конечно отлично, но вы каждый раз читаете содержимое всех js файлов.
                    Предлагаю делать так:

                    foreach ($jsFiles AS $file)
                    {
                    $compressedName .= filemtime($file).'|'.$file;
                    }
                    $compressedName = md5($compressedName);

                    if (!file_exists($compressedName))
                    {
                    // тут собираем все файлы, компрессим и записываем в $compressedName;
                    }

                    + рядом со сжатым ява-скриптом хорошо бы положить несжатый (дальше расскажу, почему)
                    + в папку с сжатым файлом можно положить такой htaccess, который обеспечит необходимый кэш

                    AddType application/x-javascript .gz
                    AddType application/x-javascript .js
                    RewriteRule ^(.*\.gz)$ $1 [L]
                    RewriteCond %{HTTP:Accept-Encoding} gzip
                    RewriteRule ^(.*\.js)$ $1.gz
                    AddEncoding gzip .gz
                    Header set ExpiresActive On
                    Header set ExpiresDefault "access plus 10 years"


                    Получается, что браузеры, поддерживающие сжатие, получат gz файл, а все остальные обычный js.
                    0
                    при использовании этой схемы браузер будет по нескольку раз загружать содержание одного и того же скрипта, используемого на нескольких страницах. Уж лучше тогда отдать всё сразу, зато на каждой следующей странице экономить один запрос.

                    кроме того, не все минимизаторы потенциально вредны: YUI compressor полностью безопасен
                      0
                      Даже если это так и gzip не кэшируется, это лучше если пользователь гуляет по сайту долго, а если это публичная часть и по статистике в среднем просматривается до 3 страниц, то математически лучше gzip. Тройку я взял из коэффициента архивации, но тут ещё такая особенность есть, что на разных страницах могут быть разные скрипты быть подключены.
                        0
                        не забывайте, что после минимизатора можно пройтись гзипом, и итоговый размер будет ещё меньше

                        вы предлагаете использовать только гзип, а я предлагаю минимизировать И использовать гзип

                        разные скрипты на разных страницах — это да, но за счет оверхеда http бывает быстрее один раз скачать 40 кб, чем 2 раза по 10 кб — и я не перепутал цифры
                        0
                        насчет YUI полностью поддерживаю, с gzip он еще и сжимает лучше, чем Packer
                        http://webo.in/articles/habrahabr/11-min…

                        Насчет того, что скрипты будут по несколько раз грузиться — тут компромисс нужен: либо быстрая загрузка всех страниц, либо минимизация трафика. В большинстве случаев на клиент отдается больше данных, но сайт "работает" быстрее при этом
                          +1
                          блин, оторвал бы разработчикам яйца уже. Задолбался править ссылки с javascript
                          http://webo.in/articles/habrahabr/11-min…
                            0
                            ну у нас пока компромисс — скрипты грузятся двумя большими блоками, один из которых не на всех страницах нужен

                            ссылки - да, я не понимаю, почему тут какой-нибудь safehtml не используют
                              0
                              :) у вас все, как у людей, сделано хотя бы. Хотя я тут статью готовлю о вреде спрайтов и альтернативных методах — твое мнение будет интересно.
                                0
                                ага, обращайся : )
                                у спрайтов есть минусы, да

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                        Самое читаемое