Улучшения Chrome и Firefox ускорили перезагрузку страниц на 28-50%


    Традиционная модель валидации ресурсов

    Разработчики из Google вчера объявили о результатах совместного с Facebook и Mozilla проекта оптимизации браузера по образцу Firefox. После оптимизации значительно ускорилась повторная загрузка страниц в мобильной и десктопной версиях Chrome. По данным Google, в последней версии Chrome перезагрузка страниц ускоряется в среднем на 28%.

    Обычно при перезагрузке страницы браузер осуществляет валидацию: отправляет сотни сетевых запросов только для проверки, что картинки и все остальные ресурсы в кэше всё ещё остаются действительными и их можно использовать повторно. Такой механизм перезагрузки страниц существовал без изменений много лет, несмотря на все изменения в сайтах и технологиях веб-разработки. Для маленьких элементов скорость выполнения этого запроса с получением ответа 304 HTTP примерно соответствует скорости обычного запроса с загрузкой элемента веб-страницы.

    Пришло время улучшить браузеры и сайты.

    Разработчик Google Такаси Тоёсима (Takashi Toyoshima) объясняет, что раньше валидация не приносила особенных хлопот, но с развитием веб-технологий сейчас на каждую страницу обычно приходятся сотни сетевых запросов, которые отправляются к десяткам разных доменов. Это особенно неприятно на мобильных устройствах, в которых пинг к серверам выше, чем на десктопе, а соединение нестабильно. Из-за больших задержек и нестабильного соединения возникают серьёзные проблемы с производительностью мобильных браузеров и скоростью загрузки страниц.

    Первыми об улучшениях браузера подумали в Mozilla. Они ещё в прошлом году внедрили в Firefox 49 поддержку функции Cache-Control: immutable. С её помощью сервер может указывать ресурсы, которые никогда не изменяются. Такие элементы никогда не запрашиваются повторно. Например, шрифты, скрипты и таблицы стилей, а также десятки изображений, которые включены в оформление страницы. Так можно оптимизировать вообще любые ресурсы. Если ресурс изменяется, то его выкладывают с другим именем (в Facebook реализована система, где имена ресурсов соответствуют хэшам их содержимого).

    В традиционной модели cache-control устанавливает ограниченное время жизни ресурса.

        $ curl https://example.com/foo.png
        > GET /foo.png
        
        < 200 OK
        < last-modified: Mon, 17 Oct 2016 00:00:00 GMT
        < cache-control: max-age=3600
        <image data>

    По истечении этого срока браузер производит проверку действительности ресурса.

        $ curl https://example.com/foo.png -H 'if-modified-since: Mon, 17 Oct 2016 00:00:00 GMT'
        > GET /foo.png
        > if-modified-since: Mon, 17 Oct 2016 00:00:00 GMT
        
        If the image was not modified
        < 304 Not Modified
        < last-modified: Mon, 17 Oct 2016 00:00:00 GMT
        
        < cache-control: max-age=3600
        If the image was modified
        < 200 OK
        < last-modified: Tue, 18 Oct 2016 00:00:00 GMT
        < cache-control: max-age=3600
        <image data>

    Параметр immutable снимает с браузера обязанность проверять действительность ресурса.

    $ curl https://example.com/foo.png
    > GET /foo.png
        
    < 200 OK
    < last-modified: Mon, 17 Oct 2016 00:00:00 GMT
    < cache-control: max-age=3600, immutable
    <image data>

    Почти в то же время, как функция появилась в Firefox, Facebook начал модифицировать серверную инфраструктуру для поддержки этой функции. Разработчики Mozilla с удовлетворением отмечают, что и другие веб-сайты постепенно внедряют эту функцию, как и Facebook.

    Разработчики Chrome тоже последовали примеру Firefox. Например, последняя версия Chrome делает на 60% меньше сетевых запросов для валидации кэшированных ресурсов, что означает ускорение скорости загрузки страниц в среднем на 28%.

    В тестах Firefox результаты подтверждаются. Вместо средних 150 запросов на страницу Firefox отправляет всего 25, а в некоторых случаях загрузка страницы ускоряется в два раза.



    Почему пользователи обычно перезагружают страницу? Обычно это происходит в двух случаях — или потому что страница загрузилась некорректно, или потому что её содержание кажется устаревшим. Механизм обновления, разработанный десятилетия назад, учитывал только первый сценарий перезагрузки. В те далёкие времена никто не мог предположить, что статические веб-страницы могут меняться ежеминутно. Поэтому старый механизм неэффективно справлялся со вторым сценарием, отправляя запросы на валидацию одних и тех же ресурсов при каждой перезагрузке страницы. Разработчики считают, что такие проверки излишни.

    Теперь Chrome и Firefox осуществляют перезагрузку страниц в упрощённом режиме — проверяются только основные ресурсы, а затем идёт обычная загрузка страницы. Такая оптимизация хороша во всех отношениях: скорость загрузки ускоряется, сетевой трафик снижается, экономится заряд батареи на мобильном устройстве. Facebook отрапортовал, что количество зпросов к статическим элементам на сервере уменьшается на 60%.

    На видео показано, как происходит перезагрузка типичной страницы на Amazon со смартфона у американского сотового оператора. Видно, что время перезагрузки уменьшается с 20 секунд примерно до 13 секунд, причём в новой версии Chrome после прихода ответа с сервера страница обновляется на экране практически мгновенно, а не загружается по частям.


    Коллеги из Facebook, которые наиболее заинтересованы в улучшении работы браузеров, помогали в разработке. Интересно, что в 2014 году инженеры Facebook провели исследование и выяснили, что именно Chrome присылает больше всего запросов, которые возвращают 304 HTTP.



    Проблема была в совсем ненужном фрагменте кода, уникальном для браузера Chrome, который очень часто активирует ревалидацию ресурсов. После устранения лишней ревалидации в 2015 году ситуация исправилась.



    Сейчас работа продолжилась, и с появлением «вечных» ресурсов обновления будут происходить ещё реже. Разработчики Chrome говорят, что данное изменение потребовало относительно небольших изменений в коде. Это наглядный пример, как маленькие оптимизации способны дать отличный результат.

    Одновременно с поддержкой immutable-элементов Facebook одним из первых сайтов внедрил сжатие brotli. С его помощью сжимается динамическая разметка, которую нельзя кэшировать. По сравнению со старым gzip, применение brotli экономит примерно 20% трафика.

    Поддержка immutable-элементов на сервере выгодна и для пользователей, и для владельца сервера, ведь снижаются трафик и нагрузка на CPU.
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

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

      +9
      Не понятно, чем immutable отличается от древнего способа установки что-т вроде
      Cache-control: max age=100000000
      Expires: 2050-10-10


      и удаления `E-tag/Last-Modified` — чтобы браузеры и не думали за 304 обращаться

        +3

        В конце 2050 года все ваши сайты резко замедлятся...

          0
          Надолго ли?
            –1

            Пока программист константу в коде не поменяет! :)

            –2
            2050 года не будет. Будет что-то другое, много позже конца Эпохи.
              0
              Конец эпохи был вроде в 2012. Там какие то траблы с календарём майя были.
                +2
                Код майя весь выпилили. От слова «весь». А вот юниксовый код — он всюду. Так что 2038 касается всех.
                  0

                  Есть мнение что к тому времени решение этой проблемы будет найдено. А константа 2050 в коде как была — так и останется :)

            +2
            Раньше даже при установке максимального времени жизни в Cache-control, хром все равно отправлял запрос на эти ресурсы в случае перезагрузки страницы (именно перезагрузки соответствующей кнопкой или комбинацией клавиш) и получал 304.
            Веб разработчики которые начинают заниматься оптимизацией статических ресурсов обязательно на это натыкались при тщательной отладке.
            Хром как раз это и пофиксил.
            0
            Лучше бы попробовали решить проблему, что на медленном соединении (64 килобита на телефоне) часто страницы загружаюьтся полностью чистыми и тест отобюражается уже после полной загрузки страницы. Как я понимаю это вызвано медленной загрузкой шрифтов и прочих элементов. Также бывает (в мобильном firefox), что страница загружается, уже вижно контент, начинаю его читать, а ниже ничего нет! Это воовсе непонятно, html страничка же загружается в самом начале, а уже потом на ней начинают навешиватсья скрипты и стили. Наблюдаю такое на мобильной версии гиктаймса в комментариях.
            Вообще, раньше было лучше: сначала загружалась страничка, её уже можно было читать, а уже потом подгружались картинки и стили.
              0
              Это воовсе непонятно, html страничка же загружается в самом начале, а уже потом на ней начинают навешиватсья скрипты и стили.

              Браузер отправляет запросы изображений стилей и скриптов до полной загрузки страницы(html). Я на бесплатном мобильном инете когда сидел наблюдал аналогичную картину. Сделал скрипт который скрывает изображения до полной загрузки страницы.

              • НЛО прилетело и опубликовало эту надпись здесь
                  0

                  Тут проблема в том что всё грузится одновременно не давая html загрузится до конца. В итоге соединение обрывается и страница остаётся не загруженной.

                0

                А мне нравится appcache. Обновление страницы и её контента проверяется одним запросом. И сайт может работать из кеша даже оффлайн. Жаль что ему установили статус нерекомендуемый но пока он всё ещё работает.

                  +3
                  Эм… А что будет если этот immutable ресурс загрузился не полностью, или скачаная версия содержит ошибку?
                  Перезагрузка страницы не поможет, тогда переустанавливать браузер? (сарказм)
                    0
                    Так кэш же почистить.
                      0

                      Вообще должен догрузить при обновлении страницы. А вот с ошибками только проверкой хеша можно бороться.

                        0

                        Просто нажать "Hard reload"

                          +3
                          На мобилке будет трудно.
                          0

                          Загрузку не полностью браузерам пора бы научиться определять самим. А обновление должно быть заботой не пользователя, а разработчика. И решается проблема просто: новая версия файла должна иметь другое имя.

                            0

                            Если есть Content-Length браузер определяет что ресурс не полностью загружен. Но догружает его при следующем открытии страницы.

                          +1

                          А что если в ответ по первому запросу к странице выдавать полный список версий ресурсов с этой страницы или просто устаревших ресурсов. Браузер смотрит что протухло, и грузит только устаревшие версии. Что-то в духе:


                          Cache-outdated: main.css, image.png, script.js


                          Или такое уже есть в симпсонах стандарте?

                            +1
                            Чтобы получить полный список ресурсов страницы придётся, в некоторых случаях, выполнить примерно тот же объем работы, что и для генерации полной страницы. Выходит лишняя нагрузка на сервер.
                              0

                              Я вот так себе это фантазирую(на примере nginx+php):
                              первый запрос: php генерирует страницу, выдает ее nginx-у, тот отдает клиенту, затем смотрит в содержимое, ищет все ресурсы, приписывает какой-то тег странице со списком ресурсов и их версий(или временем изменения), затем сохраняет страницу в свой кэш.


                              последующие запросы: nginx берет страницу из кэша, отдает клиенту. Клиент смотрит этот тэг, видит, что страница имеет следующие ресурсы A.ver123, B.ver35, Z.ver5. Смотри в свой кэш, находит эти ресурсы, если совпадают, то сразу же по ним возвращает 304 и рендерит страницу. Если же есть расхождения, то делает запросы только по ним.


                              Возможно это хорошо только для кэшируемых страниц.

                                0
                                В вашем сценарии придётся повесить на nginx задачу по парсингу содержимого (как? хорошо если оно в html или css прописано, а если там JS генерирует имена картинок по каким-то своим правилам?), заниматься кешированием (где и как долго хранить кеш?) или припиской вычисленного тэга к уже имеющемуся кешу.
                                А зачем?
                                Проблема в предложенном подходе с immutable — только одна: невозможность смены содержимого ресурса без смены его имени. Но это проблема организационная. И решение её давно придумано — называть ресурсы по хэшу их содержимого.
                                А ваша идея создаёт технические проблемы которые кому-то придется постоянно решать.
                                  0

                                  Спасибо. Сказав про имена, до меня дошел принцип работы immutable :)

                                  +1

                                  Appcache же.


                                  1. За место имён ресурсов используем хеш
                                  2. Отсылаем хедер с ними
                                    Cache-Control: immutable

                                  index.html


                                  <!DOCTYPE HTML>
                                  <html manifest="cache.appcache">
                                    <body>
                                      …
                                    </body>
                                  </html>

                                  cache.appcache:


                                  CACHE MANIFEST 
                                  /cf298295d05da05257c0cb7ce8af7dcc8ef95e35.css
                                  /2d408aaa5a340d732402a346a7f915ed8a3d8a04.js
                                  /cbb33e652dd64ca308905a138dec165c4619ae32.png

                                  В результате браузер должен запросить только новые файлы.

                                    0

                                    Да, точно, оно самое. Спасибо.

                                      0

                                      Надеюсь вы шутите :) Во-первых он deprecated, ибо теперь service workers. Во-вторых в рамках обсуждаемого вопроса, это как из пушки по воробьям. Там у этого AppCache (который вообще для offline приложений) столько нюансов…

                                    0

                                    Этот сценарий успешно реализуется в рамках текущего HTTP и именно он еще больше улучшается с введением immutable. Никакого Cache-outdated не нужно.


                                    На самом деле там все просто. Версия кодируется в имени файла, получившемуся ресурсу выставляется "вечное" кеширование. И не обязательно это делать в рантайме — такие инструменты как webpack умеют добавлять хеш содержимого в имя бандла, из-за чего версионирование получается автоматически еще на стадии сборки проекта. В крайнем случае можно в качестве версии брать хеш текущего коммита в git. Дельта-обновлений не получится — но при не очень частых обновлениях никто лишнего трафика не заметит.

                                –2

                                Странно, вроде бы фичу первым внедрил Firefox, а преподносится всё так, словно за неё надо благодарить Chrome… Ох уж эти маркетологижурналистыАлизар…

                                  +1
                                  У меня есть давняя мысль, что URL в современном мире работает не очень хорошо.

                                  Представьте себе на секунду, что мы бы говорили не про 'http', а про 'world wide git'. Страница — набор коммитов. Браузер может делать либо нормальный pull (без истории), либо скачивать только те коммиты, которые устарели.

                                  Файлы идентифицируются по хешу, т.е. устаревание файла определяется по смене хеша, на который ссылаются.

                                  Говорю это по наблюдению за браузером, когда pull для проекта проходит быстрее, чем открытие его страницы на гитхабе.
                                    +1
                                    IPFS — это одноранговая распределенная файловая система, которая соединяет все вычислительные устройства единой системой файлов. В некотором смысле IPFS схожа со всемирной паутиной. IPFS можно представить как единый BitTorrent-рой, обменивающийся файлами единого Git-репозитория. Иными словами, IPFS обеспечивает контентно адресуемую модель блочного хранилища. с контентно адресуемыми гиперссылками и высокую пропускную способность. Это формирует обобщенный древовидный направленный граф. IPFS сочетает в себе распределенную хэш-таблицу, децентрализованный обмен блоками, а также самосертифицирующееся пространство имён. При этом IPFS не имеет точек отказа, и узлы не обязаны доверять друг другу.

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

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