Вопрос, стоит ли хранить javascript и css ресурсы веб-страницы в LocalStorage браузера или позволить ему самому отрабатывать кэширование, не имеет однозначного ответа. Есть плюсы и минусы. С моей точки зрения, основной плюс — скорость загрузки — перевешивает все остальное. Это очень хорошо чувствуют пользователи EDGE и 3G.

Для поклонников стандартного кэша браузеров, гордо показывающих на слово «Кэшировано» в Средствах разработчика, советую открыть Fiddler и увидеть, что по каждому кэшированному ресурсу за 304 HTTP ответом всё равно идет запрос. Затем советую зайти на что-нибудь типа pingdom.com и увидеть, что непосредственно передача данных во всем времени исполнения запроса занимает проценты. То есть толку в абсолютном значении от такого кэширования — кот наплакал, особенно если файлы небольшие.

Предлагаемая схема хранения ресурсов в LocalStorage достаточно проста.

Во-первых, реализовано отслеживание изменения файлов, для этого используется время последнего изменения файла как его «версия». При его изменении ресурс перегружается в локальное хранилище.

Ресурс линкуется следующим образом:

<script type="text/javascript">
	<?php include("ls.js"); ?>

	requireResource(
		'mobile.css', 
		'css', 
		'<?php echo filemtime(__DIR__ . "/css/mobile.css") ?>', 
		'<?php echo "/css/mobile.css?" . filemtime(__DIR__ . "/css/mobile.css") ?>');	
</script>

Функции requireResource передается название ресурса (под этим именем он пойдет в локальное хранилище), тип, версия и url ресурса. Логика кода ls.js простая — если ресурс есть в хранилище и версия его совпадает с указанной — инлайнится он. Если нет — грузится заново, помещается в хранилище и инлайнится в HTML код.

function _cacheResource(name, t, version, url) {
    var xmlhttp = new XMLHttpRequest(); // code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4) {
        if (xmlhttp.status == 200) {
          localStorage.setItem(name, JSON.stringify({
            content: xmlhttp.responseText,
            type: t,
            version: version
          }));
        } else {
          console.warn('error loading '+url);
        }
      }
    }
    xmlhttp.open("GET", url, true);
    xmlhttp.send();
  }

function _loadResource(url, type, name, version, callback) {

  if (type == "js") {
	document.write('<script id="' + name + '" src="', url, '"><\/script>\n');
  } else if (type == "css") {
	document.write('<link id="' + name + '" rel="stylesheet" href="', url, '" />\n');
  }
  var s = document.getElementById(name);

  if (s.readyState) { //IE
    s.onreadystatechange = function() {
      if (s.readyState == "loaded" || s.readyState == "complete") {
        s.onreadystatechange = null;
        _cacheResource(name, type, version, url);
        if (callback) callback();
      }
    };
  } else { //Others
    s.onload = function() {
      _cacheResource(name, type, version, url);
      if (callback) callback();
    };
  }

}

function _injectResource(content, url, name, version, callback) {
  var c = JSON.parse(content);
  // cached version is not the request version, clear the cache, this will trigger a reload next time
  if (c.version != version) {
    localStorage.removeItem(name);
    _loadResource(url, c.type, name, version, callback);
    return;
  }
  if (c.type == "js") {
	var s = document.createElement('script');
	s.type = "text/javascript";
  } else if (c.type == "css") {
	var s = document.createElement('style');
	s.type = "text/css";
  }
  var scriptContent = document.createTextNode(c.content);
  s.appendChild(scriptContent);
  document.getElementsByTagName("head")[0].appendChild(s);
  if (callback) callback();
}


function requireResource(name, type, version, url, callback) {
  var c = localStorage.getItem(name);
  if (c == null) {
    _loadResource(url, type, name, version, callback);
  } else {
    _injectResource(c, url, name, version, callback);
  }
}

Есть выбор как инлайнить код — или через document.write(); или через вставку элемента в DOM. В первом случае мы получаем копию того, как если бы ресурс подцеплялся самой страницей. Второй, в свою очередь, логически более правильный, но есть минусы — js код не исполняется, например. Нужно в ручном режиме проводить инициализацию — что несложно, но нужно об этом помнить.

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

В данном примере используется 2 типа ресурсов — js и css. В принципе, можно расширить на всё, что можно сериализовать в локальное хранилище браузера.

Результат очевиден — мои css и js файлы больше в Средствах разработки браузера и Fiddler'e не появляются (если не происходит их обновление на сервере). Сайт открывается ощутимо быстрей. Процесс js и css дебага на продакшне затрудняется не сильно. А на девелопмент машине все js и css файлы грузятся по отдельности для удобства работы.

Нужно учитывать, что средства замера скорости и производительности сайта типа Google Pagespeed не понимают такого самодельного кэширования и не покажут прироста производительности.

Основа js кода взята с GitHub и доработана.

Комментарии (111)


  1. Sombressoul
    28.04.2018 19:22

    WebPack + If-Modified-Since

    Не проще ли?


    1. KYuri
      28.04.2018 19:47
      +1

      «If-Modified-Since» — это дополнительный запрос.

      Идея автора статьи другая:

      • в теле html-файла передать «версию» ресурса
      • клиентским JS-ом сравнить «версию» ресурса на сервере и в localStorage
      • при совпадении «версии» — взять из localStorage
      • при различии «версии» — отправить запрос на сервер


      Идея (в теле html-файла перавать «версию» ресурса) — правильная.
      А вот использовать для всего остального JS — спорное решение. Навскидку:
      • при отключенном JS-е ресурсы не будут загружены вообще
      • даже если JS работает, будут сломаны все браузерные оптимизации по предсказанию и предзагрузке ресурсов. В результате может оказаться, что авторская версия, даже не выполняя запросов в сеть, будет медленнее, чем могла бы.


      1. altrus Автор
        28.04.2018 20:01

        Ваше замечание насчет отключенного JS верно, и относится к определенной категории сайтов. Мой лично — как и 95%+ других, наверно — без JS не работает, так что это обязательно.
        Насчет браузерных оптимизаций не понял. Пример?


        1. KYuri
          28.04.2018 20:44

          Браузер, получая из сети html, пытается сразу же (прям в процессе получения) парсить, анализировать что можно, и использовать данную информацию.

          Вариант 1
          <!DOCTYPE html>
          <html>
          <head>
              <link href="css/main.v1.css" rel="stylesheet"/>
          </head>
          <body>
            ... BIG_CONTENT ...
          </body>
          </html>


          1. altrus Автор
            29.04.2018 04:05

            Всё это верно, но к моему случаю не относится. В то время, как браузер дойдет до строки, подключающей mobile.css, там будет или уже код css из localStorage, или ссылка на ресурс, если он незакэширован. Так что проявить свой «интеллект» у браузера шансов не будет )


      1. Sombressoul
        28.04.2018 20:12

        Я потому про связку с WebPack и упомянул, что это (для JS, в частности), уверенный и стабильный +1 запрос (в подавляющем большинстве случаев возвращающий в респонсе только заголовки — это сущие байты).

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


        1. altrus Автор
          28.04.2018 20:19

          Мы, по-моему, говорим о разных вещах. Все js (как и css) файлы на продакшн сервере у меня и так в один скомпонованы без всяких WebPack-ов. Статья не об этом.


        1. KYuri
          28.04.2018 20:52

          Да, получим «уверенный и стабильный +1 запрос».
          И до кучи — увеличение вероятности, что придётся перекачивать весь бандл :)


  1. KYuri
    28.04.2018 19:24
    +1

    Для поклонников стандартного кэша браузеров, гордо показывающих на слово «Кэшировано» в Средствах разработчика, советую открыть Fiddler и увидеть, что по каждому кэшированному ресурсу за 302 HTTP ответом всё равно идет запрос

    Во-первых, не 302 («Moved Temporarily»), а 304 («Not Modified»).

    Во-вторых, запрос браузером закэшированного ресурса говорит о том, что браузер «сомневается» в актуальности кэшированных данных.
    Однако существуют механизмы, «убеждающие» браузер в том, что его кэш не требует ревалидации (cache-control immutable).
    Ваша реализация («используется время последнего изменения файла как его «версия»») вполне себе закрывается данным механизмом. Причем будет работать даже при выключенном/заблокированном JS в браузере.


    1. altrus Автор
      28.04.2018 19:55

      С 302 ошибся, спасибо.
      По поводу cache-control immutable — как я понимаю браузерная поддержка пока слабая, особенно для смартфонов.


      1. KYuri
        28.04.2018 21:06

        Статьи о «cache-control immutable» — с начала 2017 года.
        Тут вот даже ссылки есть на записи в багтрекерах разных браузеров.

        Думаю, что сейчас проблематично будет найти браузер (в том числе и мобильный) без поддержки «cache-control immutable».


        1. altrus Автор
          29.04.2018 03:39

          Простите, Вы на поддержку браузерами смотрели?


          1. Sabubu
            29.04.2018 16:56

            Вы про expires слышали? Этот заголовок в RFC с появления HTTP/1.1, я специально протестировал, работает в FF3.6.

            Попробуйте следить не только за нововведениями, а изучить основы веб-разработки. Про кеширование в HTTP я читал статью еще 10 лет назад, и тогда уже все работало. Как можно об этом не знать, но при этом интересоваться какими-то неработающими технологиями, я удивляюсь.


          1. Andre_487
            01.05.2018 00:24
            +1

            Там почему-то неправильные данные. Указано, что Chrome не поддерживает, но это не так. Можно убедиться на практике – попробовать отдать этот заголовок на каком-то ресурсе и попробовать нажать Ctrl+R – если он в кэше, и кэш ещё валиден – ресурс не будет скачан.


      1. Andre_487
        01.05.2018 00:22
        +1

        Уже вполне неплохая. Chromium поддерживает, так же как и Safari. Так что уже можно – мы пользуемся, например


  1. SanSYS
    28.04.2018 19:29
    +1

    Если в лимит localStorage влезаете, то наверн ок, но к чему такая динамика?

    Рассматривали возможности Html5 Application Cache?

    Вот тут скрин с фиддлером — style.css запрошен лишь раз


    1. altrus Автор
      28.04.2018 19:47

      Насколько я понимаю, при Html5 Application Cache невозможно обновление только одного ресурса — обновляются все скопом. При редких апдейтах сайта — да, удобней, особенно учитывая, что можно хранить шрифты и статичную графику; при относительно частых (мой вариант) — не очень. Можно комбинировать.
      Не знал про Application Cache, честно говоря, спасибо за наводку.


    1. KYuri
      28.04.2018 19:50
      +1

      Не надо выкапывать стюардессу — application cache уже deprecated :)


      1. SanSYS
        28.04.2018 20:19

        ох, как я устарел ))
        Спасибо, за поправку

        Use Service Workers instead

        Забавно, а с ними уже столкнулся на вебпушах, но только немного по фану, в прод на жс не пишу давно


      1. ivan386
        29.04.2018 07:49

        Ну пока он работает его можно использовать. А работать он будет скорей всего долго.


  1. demimurych
    28.04.2018 21:56
    +2

    При правильно выставленных заголовках (Cache-Control, Last-Modified и Expires) повторный запрос 304 отправляется только при нажатии CTRL f5 в webkit браузерах и по F5 в фаерфоксе. Либо по достижение Expires.
    При типичном использовании(когда пользователь не касается F5) никаких повторных запросов не отправляется.

    При этом существуют техники которые заставляют браузер всегда брать обьекты из кеша, вне зависимости от F5 или CTRL f5.

    Идее хранить css js и даже шрифты в localstrage сто лет в обед. И не прижилась она по нескольким причинам:
    1. вся работа с localstorage снихронна, что означает — если какая то вкладка по каким то причинам запустить длинную операцию с storage то ваш влкадка будет ждать ее завершения.

    2. операция stringify не бесплатна. И уже на обьектах в 40 — 100кб вы получите 40мс на десктопе задержку что больше чем если бы браузер сам взял обьекты из своего кеша. (а на мобильный платформах и того больше).

    3. Закешированые браузером обьекты генерируют запрос 304 только в случае неверных изначально заголовков кеширования или (в зависимости от браузера) по нажатию f5 или ctrl f5

    4. при загрузке ресурсов(css, js, img и так далее) по необхъодимости, а не сразу всего и сразу, даже нажатие ctrl f5 не заставит браузер слать запрос 304, а будет брать их из кеша.

    В результате, выгода от local storage только в том случае когда вы:
    А) не можете конфигурировать свой веб сервер для правильной отдачи заголовков для кеширования.
    Б) если пользователь на очень медленном соединении по каким то причинам давит часто f5 у вас на сайте, при этом вы не используете «умную загрзуку» необходимых для страницы ресурсов.


    1. altrus Автор
      29.04.2018 03:37

      1. В рассматриваемом случае задержек нет
      2. Это на порядок (порядки) меньше затрат на запрос за 304 ответом
      3. и 4. Откройте Fiddler


      1. AEP
        29.04.2018 04:47

        А разве fiddler не отключает кеш?


        1. altrus Автор
          29.04.2018 05:09

          Как и зачем ему это делать?

          Очень информативное чтиво по теме браузерного кэша, 304 ответов и прочего от создателей Fiddler:
          https://www.telerik.com/blogs/understanding-http-304-responses


      1. demimurych
        29.04.2018 14:28

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

        1. В вашем конкретном случае это так. Почему? Потому что у вас одна вкладка с таким запросом. Создайте вторую страницу и обратитесь в стораже, одновременно с этим вызовите у себя. Обнаружите то о чем я говорил. Теперь представьте ситуацию. Все поняли как здорово использовать локал стораже для хранения таких больших обьектов и стали массово его использовать. Очень нередки случаи когда у людей по десятку активных вкладок.

        2. Повторяю, запрос 304 не шлется при правильных заголовках Cache-Control, Last-Modified и Expires. Подымайте свой сервер. На нем разворачивайте проект. Поставьте для простой html странички cache-control паблик с max-age далеко в будущем. Аналогично для epxires. и ласт модифай в прошлом. Уберите etag заголовок. Открывайте в браузерах смотрите логи — смотрите результаты. Будет именно то что я Вам, (и не только я) говорю. Запросы 304 при таких случаях посылаются только в случаях что я обозначил выше.
        Важное замечание. Ресурсы которые грузятся с параметрами кешируются по другой схеме.
        Иначе говоря поведение при загрузке my.js и my.js?123 принципиально разное. Потому что в этом случае браузеры понимают такие ресурсы как динамические.

        Я никогда не пользовался Fiddler. И не в курсе как он работает. Поэтому ничего о нем сказать не могу, кроме того, что любой посредник между сервером и клиентом может искажать результаты.

        Об умной загрузке.
        Загрузка любого веб приложения можно разделить на два этапа. Первый — это загрузка всего что нужно для первого экрана пользователя. Тут нужно влезть в 14 килобайт (все вместе html css и т.д.). И второй этап загрузка всего что может понадобится после.
        То есть загрузка десятков килобайт javascript кода css файлов и прочего прочего должно идти после того как бразуер отрендерил первый экран пользователя.
        «После того» тоже бывает разным. Можно опять же пытаться грузить все одним файлом как только это потребуется, или появилось время. А можно грузить отельными небольшими порциями. Все это сильно зависит от обстоятельств работы приложения и соответствующей конфигурации серверной части. Потому что, универсального варианта нет. В одном случае будет выгодно загрузить все сразу во второй фазе. В другом случае грузить десятки файлов под каждую конкретную задачу.

        Так вот, возвращаясь к нашему вопросу. Все ресурсы (с правильными заголовками) загруженные во второй фазе, будут браться из кеша всегда если они там лежат, без дополнительных запросов. Исключение Firefox который по ctrl f5 все же пошлет для изображений 304. Для прочих ресурсов нет.


        1. altrus Автор
          29.04.2018 16:58

          Начну с конца — в FF и js и css ресурсы (не только картинки) по F5 лезут за 304 ответом — проверял сегодня на тестовой странице. По ctrl+f5 все обновляется.

          Во-вторых, у вас вариант когда браузер может то запросить ресурс, то не запросить (про F5 точно выяснили, но наверно есть и другие нюансы браузерной логики, которые гарантировать нельзя). У меня вариант, что он запрашивает ТОЛЬКО ТОГДА, когда ресурс меняется и его надо обновить. Для меня лично выбор очевиден, другим ничего не навязываю. Просто поделился.

          В-третьих, вы советуете мах-age поставить. Но у меня сайт развивается, css и js частенько меняются, что делать? Параметр после "?" использовать нельзя, как вы сами сказали, значит нужно менять имя? Некрасиво, как по мне. Да и кэш браузерный захламлять.

          Про вкладки не понял. Вы апеллируете, что для каждой вкладки будет запускаться движок локал стораджа с моими 500 кб и это нагрузит систему?
          Вот смотрите, у меня сейчас около 20 вкладок открыто, полдня где-то. Я не работаю, просто читаю-пишу в нете. Вот загрузка:
          image
          Вы найдете там несчастные 500 кб моих скриптов и стилей?

          Про умную загрузку понял. Вы бы о ней Google рассказали с его сайтами)
          Я хочу, чтобы при показе первого экрана пользователь сразу мог кликнуть на меню и оно открылось. Чтоб он не кликал и не расстраивался, что оно заработает только через несколько секунд. Для этого надо загрузить JQuery и 70% (по весу) скриптов. Какой смысл разбивать? Нету. Я пробовал, правда. И css и js 30%-70% нужно вверх. Такой сайт и менять его поведение я не буду, потому что оно хорошее. Вместо этого кэш в локал сторадж решает все проблемы. Топор тоже не предназначен гвозди забивать, но прекрасно справляется с этой работой.


          1. Sabubu
            29.04.2018 17:06
            +1

            > Начну с конца — в FF и js и css ресурсы (не только картинки) по F5 лезут за 304 ответом — проверял сегодня на тестовой странице. По ctrl+f5 все обновляется.

            Ну так правильно, пользователь просит обновить страницу с сервера, браузер это делает. Так и должно быть.

            > У меня вариант, что он запрашивает ТОЛЬКО ТОГДА, когда ресурс меняется и его надо обновить.

            Как принудительно обновить страницу с сервера в обход кеша?

            > Параметр после "?" использовать нельзя, как вы сами сказали, значит нужно менять имя?

            Во-первых, можно, он наверно ошибся, во-вторых, можно менять имя папки: /css/v11/styles.css. Вы бы основы протокола HTTP изучили, глядишь и не пришлось бы кривые велосипеды изобретать.

            > Вы апеллируете, что для каждой вкладки будет запускаться движок локал стораджа с моими 500 кб и это нагрузит систему?

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

            > Я хочу, чтобы при показе первого экрана пользователь сразу мог кликнуть на меню и оно открылось.

            У вас же блокирующий код с document.write. Почитайте про асинхронную загрузку скриптов на досуге.

            > У меня все работает

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


          1. demimurych
            29.04.2018 17:17
            +1

            1. Об отличии в поведении FF и webkit браузеров я писал с самого начала. FF всегда пошлет 304 по f5 на те ресурсы которые были обьявлены на тсранице. webkit Только по ctrl f5.
            2. Браузер что FF что webkit НИКОГДА не запросит даже 304 если ресурс подгружался динамически во второй фазе. Исключение если ресурс грузится с параметром.
            3. Да менять имя. И так это и делают все нормальные люди. Меняют имя не руками конечно. Какое в проекте имя и какое отдается в страницу — вопрос организации работы. Кеш так вы не захламите. Браузеры очень оперативно исключают из кеша то, что не используется даже с большим max-ege.
            4. по вкладкам, я имел ввиду когда много разных ресурсов начнут активно пользовать большой обьем данных в локалстораже. В результате вы получите ситуацию когда ваша вкладка может висеть и ждать своей очереди.
            5. Гугл именно так и работает везде где это возможно. Откройте google.com и посмотри в его внутренности. Подымите свое понимание относительно того, как писать быстрые страницы на новый уровень. А для гугла, каждая миллисикунда стоит больших денег. Кстати в гугловсом Pagespeed тесте этому уделяется очень большое внимание.
            6. То что Вам для работы меню нужен JQuery говорит о том, что вы неправильно выбрали инструмент для решения своих проблем. В настоящий момент просто открытие меню со свистоперделками можно писать на чистом CSS без javascript кода вообще. Или с минимальным кодом в несколкьо команд.

            Главное.
            Вам не только я пытаются сказать, что в вашем материале неверный посыл. Работа через LocalStorasge имеет смысл только в очень специфической ситуации (неспособность правильно выставить заголовки кеширования на веб сервере). Во всех же остальных случаях, работа с кешем бразуера не хуже, а зачастую лучше чем велосипед с LocalStorage, который может еще и вредить производительности.

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


            1. altrus Автор
              29.04.2018 17:33

              Вы сейчас всех веб-разработчиков, использующих JQuery, загнали в стойло лузеров )

              У нас с вами просто разное понимание о том, какой должен быть сайт, разные сферы деятельности. Нет общего предмета обсуждения.


              1. demimurych
                29.04.2018 17:36

                Нет. Я просто сказал что JQuery это отличный инструмент для своих задач.
                Мой текущий предмет деятельности — это миллисекунды которые нужно выиграть чтобы проект работал быстро. И это не зависит от того что перед Вами — сайт или веб приложение. Методы для оптимизации этого едины.

                Вы в своей статье даете вредный и чудовищно неправильный посыл.
                О чем я еще раз заявляю. И подчеркиваю — ТАК ДЕЛАТЬ НЕЛЬЗЯ.


        1. Sabubu
          29.04.2018 17:00

          Да автор просто ничего не понимает. Я про кеширование, про Expires и Last-modified читал еще 10 лет назад — тогда это была горячая тема, а сейчас все уже давно придумано и изобретать тут нечего.


      1. Sabubu
        29.04.2018 16:59

        Хватит писать фигню. Я тестировал на встроенном в PHP веб-сервере в FF3.6 — он показывает, что ресурс, закешированный через expires, не запрашивается при переходе на другую страницу. А вам сообщу, что часто в браузерах при открытии инструментов разработчика отключается кеш.


    1. altrus Автор
      29.04.2018 09:17

      Объясните, пожалуйста, что такое «умная загрузка»?


  1. PaulMaly
    28.04.2018 22:08

    Идея ооочень старая. Лет 5 назад юзал на парочке SPA с помощью github.com/TradeMe/bootup.js. Давно отказался, все же localStorage для другого создавался.


    1. altrus Автор
      29.04.2018 03:28

      Какая разница для чего создавался localStorage, если это работает и дает ощутимую выгоду для пользователя?


      1. PaulMaly
        29.04.2018 23:43

        Да просто есть инструменты, которые как раз создавались для этого. Не понимаю любовь к велосипедам эксплуатирующим инструменты созданные для другого.

        По моему мнению, в целом данный способ рабочий, но для очень узкого спектра веб-приложений. В основном SPA. Сам использовал и для тех задач, это было норм, но с появлением Service Worker данный велосипед вообще теряет смысл.


        1. altrus Автор
          30.04.2018 03:34

          Напишите разъяснительный пост на хабре как с помощью Service Worker кэшировать ресурсы. буду благодарен.


          1. kahi4
            30.04.2018 09:15
            +1

          1. PaulMaly
            30.04.2018 09:47
            +1

            А поиск вам на что? Вот, например, уже написанный пост: Service Workers. Инструкция по применению. (https://habr.com/post/345552/). Там и про localStorage упоминается.


            1. altrus Автор
              30.04.2018 10:35

              Хорошая статья, спасибо.
              Только я не совсем понял, почему в localStorage не следует хранить свой css, а через Service Workers можно.
              Концептуально, кроме синхронности localStorage в чем проблемы?
              Понятно, что Service Workers удобней и функциональней, но почему кэшировать пару текстовых файлов в localStorage вредно?


              1. PaulMaly
                30.04.2018 12:21

                Я не пытаюсь вас убедить в том что это вредно. На самом деле для некоторых типов проектов, например, каких-то простеньких браузерных игр, это даже полезно. Можно сказать, что это некий вид «инсталяции» веб-приложения прямо на устройство пользователя. Если веб-приложение подразумевает подобный механизм, т.е. пользователь ожидает чего-то подобного, то почему бы и нет. Этого явно не подразумевают обычные веб-сайты и большая часть SPA приложений тоже. К тому же, при наличии достаточного количества ассетов, например графики, объем localStorage довольно быстро переполняется и нужно искать комбинированные решения.

                Из очевидных минусов этого подхода, по сравнению с Service Worker:

                1. Создан как хранилище ключ-значение, а не для кэширования файлов, поэтому может иметь ряд ограничений для этой цели как в настоящем, так и в будущем.
                2. Имеет синхронный интерфейс и управляется из js, т.е. «вешает» страницу и вообще не работает если вдруг наблюдаются проблемы со скриптами (на мобильном интернете это сплошь и рядом)
                3. В отличие от Service Worker, который просто прокси, полностью подменяет собой браузерные механизмы загрузки ресурсов, что может быть чревато. Service Worker подключается 3-мя строчкам и ничего не ломает, даже если браузер его вообще не поддерживает.


                Из плюсов этого подхода, которые лично мне импонировали 5 лет назад, когда я его использовал:
                1. Единственный способ нарисовать более-менее «честный» прогресс-бар.
                2. Единственный способ действительно грузить ресурсы параллельно (обычно 7 потоков) во всех бразуерах начиная с IE 8


                1. altrus Автор
                  30.04.2018 12:46

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

                  Я не призывал пихать в localStorage графику и шрифты. Не говорил, что это универсальное решение. Конкретно по моему случаю — пара текстовых ресурсов, оба в любом случае грузятся блокирующими синхронными запросами (и синхронность localStorage тут естественна — просто один программный поток). localStorage я использую просто как глобальную переменную — он для этого и создан. Сравнивать его по функционалу и предназначению с Service Worker все равно что сравнивать массив строковых переменных и программный фреймворк со своей базой данных.

                  У меня стояла небольшая локальная задача, я ее решил так. Пользователю это не вредит — если браузер выделяет под это 5 мегабайт, то, наверное, подразумевается, что там не только коротенькие имя-фамилия юзера будут храниться. Поднявшийся антагонизм не понимаю…


                  1. PaulMaly
                    30.04.2018 17:15
                    +1

                    Честно говоря, в вашем случае смысла действительно нет особого. Нравится — используйте, но как я понял сообщество взъелось лишь из-за того, что вы советуете это другим. Многие не смогу верно оценить пользу и вред, особенно если пример вашего сайта действительно не показателен. Я бы тоже рекомендовал перейти на Service Worker. Вам даже делать ничего не придётся, например можно взять: github.com/GoogleChromeLabs/sw-toolbox и 3 строки кода.


                    1. altrus Автор
                      30.04.2018 18:00

                      Не думаю, что после этого поста за мной последуют толпы последователей.

                      Я смотрел Service Worker, мне понравилось. В будущем перейду. Единственное, на самом деле что пока не дает — необходимость https. У многих моих пользователей слабый инет, а я как-то долго сидел на EDGE с максимум несколькими кб в секунду. Так вот на такой скорости разница между http и https дискретная — первый как-то качает, второй — нет.


                      1. PaulMaly
                        30.04.2018 18:38

                        Вам ваша специфика виднее, но лично я ратую за использование SSL повсеместно.


  1. nazarpc
    28.04.2018 22:22

    Вопрос, стоит ли хранить javascript и css ресурсы веб-страницы в LocalStorage браузера или позволить ему самому отрабатывать кэширование, не имеет однозначного ответа

    Вообще-то есть, и это однозначно нет.


    Для этой задачи есть Cache API или на крайний случай IndexedDB, что вместе с Service Worker является стандартом де-факто в современных приложениях, нацеленных на работу offline.


    1. altrus Автор
      29.04.2018 03:28

      Обоснуете однозначность ответа?

      Cache API экспериментален и не поддерживается в некоторых браузерах, работает только по https — я теряю на нем 95% своих пользователей
      IndexedDB сложен и сам по себе, и для этой задачи. Микроскопом заколачивать гвозди


      1. nazarpc
        29.04.2018 11:38

        localStorage это синхронное хранилище для текстовой информации небольших объемов. Тут нечего больше объяснять.

        Cache API и правда не поддерживается в старых браузерах. Оставьте их в покое, если обновляться не хотят. Про HTTPS есть Let's Encrypt, так что если вы уважаете ваших пользователей, у вас нет никакого оправдания не включать HTTPS на всех сайтах что под вашим контролем.

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


        1. altrus Автор
          29.04.2018 11:47

          5 мегабайт на текстовую информацию небольших объемов — противоречия не находите?
          Что за текстовая информация размером в мегабайты?
          Неудовлетворительное объяснение.

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


          1. nazarpc
            29.04.2018 12:21

            Нет, не нахожу. 5МиБ это совсем не много. А если засунете туда пару неизбежно связанных с CSS картинок в base64 и место закончится. Не говоря о том, как неудобно и медленно оттуда синхронно доставать данные.


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

            Ознакомьтесь с HTTP/2. А потом серьезно пересмотрите критерии оценки уважения к пользователям.


            1. altrus Автор
              29.04.2018 12:41

              У меня и моих пользователей пока что там прекрасно лежат 400 килобайт css и js в виде простого текста, которые очень быстро (относительно ненужных HTTP запросов) оттуда достаются, и не понимаю, чем вам это так сильно не нравится


              1. redfs
                29.04.2018 13:41

                Вообще nazarpc понять гораздо легче, чем вас. На чем вы экономите? На двух запросах (css + js), которые потенциально могут вернуть 304? Тогда вопросы — а сколько изображений на типичной странице вашего сайта? Никаких счетчиков конечно же на странице нет?

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


                1. altrus Автор
                  29.04.2018 13:58

                  Картинки не играют никакой роли. У них вообще lazy load

                  До того, как пользователь увидит буковки в открывающейся странице и начнет читать, должно произойти, грубо говоря, 3 запроса:
                  1. к странице
                  2. к css файлу
                  3. к js файлу

                  Это блокирующие запросы браузера. Я экономлю на 2 запросах из 3. Еще раз, если вы посмотрите время выполнения запросов на pingdom.com, например, то увидите, что пустой запрос за 304 ответом отнимает примерно столько же времени, как и запрос за ресурсом в несколько десятков килобайт. В зависимости от типа сети.

                  Итого в среднем я выигрываю пускай примерно 50% времени от клика пользователя на ссылку до появления на экране страницы.
                  Так понятней?
                  Дело не в объеме скачанной информации, а времени появления страницы. Три запроса.


                  1. redfs
                    29.04.2018 14:33

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

                    Мне все-таки как то понятнее вот так:

                    window.onload is not the best metric for measuring website speed
                    (с) Steve Souders
                    Источник, 5 лет статье


                    1. altrus Автор
                      29.04.2018 16:19

                      Google Pagespeed и другие метрики считают по-другому. Основной критерий оптимизации сайта там — скорость появления текста на экране. И это правильно.


                      1. redfs
                        29.04.2018 20:05

                        Мне кажется, что тенденция все-таки — First Meaningful Paint (FMP) — первая значимая отрисовка. Вы и сами знаете, что пользователь сильно не любит, когда страницу «колбасит» и чаще всего просто ждет полной отрисовки контента. Я говорю о посетителях сайта, а не о всяких там SEO-шных заморочках.


                        1. altrus Автор
                          30.04.2018 04:34

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


                          1. redfs
                            30.04.2018 08:50

                            Нет, ваша технология заточена на другую метрику — First Paint (FP) — первая отрисовка.


                  1. Sabubu
                    29.04.2018 17:07

                    Позвольте внести вклад в ваше образование. Если вы освоите асинхронную загрузку скриптов, то вам хватит только 2, а не 3 запросов, для отображения страницы.


                  1. iproger
                    29.04.2018 18:27

                    Вы написали что картинки у вас lazy load. Это когда заходишь на сайт, начинаешь прокрутку и наслаждаешься как колбасит страницу от появляющихся изображений? Да, и это все ради мегабайта-двух?


                    1. altrus Автор
                      30.04.2018 03:42

                      Нет. Картинки у меня плавно появляются не двигая разметку. Например, в блоге, изначально на месте картинок находятся заголовки статей. Затем всплывает картинка, заголовок плавно меняет свой цвет с темного на светлый и становится капшном картинки с полупрозрачным темным оверлеем.
                      Размер шрифта заголовка вычисляется заранее таким образом, чтобы заголовок не занимал больше 50% площади картинки.
                      Если пользователь прокручивает экран неспеша (со скоростью чтения) картинка успевает загрузиться и вставиться до момента появления ее в видимой части экрана.
                      Вот так это работает. Мне нравится.
                      Причем тут «мегабайта-двух» не понял.


                      1. redfs
                        30.04.2018 09:54

                        Так это тоже важное примечание к вашей статье (кроме медленного канала).

                        Т.е. для того, чтобы посетитель сайта видел хоть какой-то эффект от применения данной технологии верстка сайта должна соответствовать следующим требованиям: 1)… 2)… 3)…

                        Кмк, овчинка выделки точно не стоит.


  1. dmitryklerik
    29.04.2018 07:21

    Для того чтобы указать браузеру что нет нужны каждый раз проверять ресурс и получать 304 ответ достаточно указать expires в будущем и большой max-age в cache-control, например:
    expires: Mon, 12 Oct 2037 00:00:00 GMT
    cache-control: public, max-age=315360000

    developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=ru


    1. altrus Автор
      29.04.2018 08:22

      F5 в Файрфоксе наплевать на эту комбинацию хидеров. А не должно быть.


      1. kahi4
        29.04.2018 10:18
        +2

        А может быть наоборот игнорирование кеша по f5 фича, а не баг?


        1. altrus Автор
          29.04.2018 10:44

          Я не даю оценку, баг это или фича. Я констатирую факт, что из-за этого у пользователей моего сайта будут лаги при прорисовке браузером страниц.


          1. kahi4
            29.04.2018 11:15

            Игнорирование Кеша сделано намеренно, на случай, если в кеш попало что-то, что не должно было. В вашем варианте такого решения нет (нажать ctrl+shift+r знают и умеют многие, чистить localstorage — я бы тоже не допер)


            1. altrus Автор
              29.04.2018 11:22

              Естественно нет, и не может быть, потому что localstorage — часть приложения-сайта, и ничего туда случайно попасть не может. Приложение само решает своей логикой, что и как там чистить.
              Вы в папку temp винды часто лазите чистить, или в реестровые ветки различных программ? А в localstorage вам зачем лазить без особой надобности?


          1. YemSalat
            29.04.2018 12:16

            Я констатирую факт, что из-за этого у пользователей моего сайта будут лаги при прорисовке браузером страниц.

            Только если они жмут Ф5 (что, кстати, обосновывает проверку локального кэша через отправку ХЭД запросов) при обычном переходе по ссылкам фаерфокс для закэшированных ресурсов сеть дергать не будет.


            1. altrus Автор
              29.04.2018 12:32

              Обычные переходы внутри сайта у меня и так на XHR реализованы. Мне важны заход на сайт и F5.

              Я так и не могу четко услышать «минусы» моего подхода, кроме «локальное хранилище для этого не предназначено».
              «Минусы» кэша браузера есть — бесполезные походы за 304 ответом. А «минусы» кастомного кэша в локальном хранилище?


              1. kahi4
                29.04.2018 12:39

                Помните, я говорил, что localstorage чистится в случайное время? Так вот, он не чистится. В итоге если пользователь хоть раз зашёл и ушёл навсегда — ваши данные будут впустую захламлять ему место. К счастью, от этого решения 5 лет назад все отказались и забыли о нем.


                Ещё недостаток — мне было бы неприятно, если бы моя страница фризилась на пол секунды. А ещё веб воркер гораздо лучше подходит — клиент не будет вообще ни за какими данными кроме небольшого json с текстом ходить и работать будет мгновенно.


                1. altrus Автор
                  29.04.2018 12:48

                  Полагаю, мои 400 кб данных не сильно утяжелят его терабайтный диск с кучей реально ненужного хлама )
                  Это единственный «минус»?
                  Вебворкер, наверное, действительно лучше подходит, поизучаю (для шрифтов и картинок). Но по эффективности мой метод предпочтительней. хотя бы потому. что он уже работает.

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


                  1. kahi4
                    29.04.2018 13:06

                    https://developer.mozilla.org/ru/docs/Web/HTTP/%D0%9A%D1%8D%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5#Freshness


                    Вообще тут великолепно описано что и как. И самый простой и эффективный и правильный способ — Cache Control. И никаких там 304 не бывает (если ресурс еще не expired). И никаких лишних запросов. Повторюсь, в Fiddler это сделано намеренно (им проще с 304 жить).


                    Полагаю, мои 400 кб данных не сильно утяжелят его терабайтный диск с кучей реально ненужного хлама )

                    Вообще не сочтите за наезд, но 400 кб данных у пользователей с терабайтными дисками и жаловаться на скорость загрузки — я представить себе такую задачу не могу. Либо у пользователь мобильные телефоны с GPRS и надо бы переделать с 400кб на не более ста, сперва, да и вообще чем больше отдаст сервер уже зарендеренного, тем лучше, либо проблема высосана из пальца и решается политиками кеша и CDN. (А еще один сайт 400кб, второй, а через месяц вникуда отожраны пару ГБ. У меня, например, на походном ноуте 128 гб памяти, а не терабайты и я там подсчитываю кто обнаглел).


                    • Service workers, не web workers, попутал немного.


                    1. altrus Автор
                      29.04.2018 13:19

                      Повторюсь, в Fiddler это сделано намеренно (им проще с 304 жить).

                      Ну объясните мне, пожалуйста, каким образом Fiddler влазит в политику браузера — посылать запрос к ресурсу ли нет?

                      У пользователей средние телефоны, средние компьютеры, и плохая сеть. Провинция, ничего необычного. Ключевое слово — плохая сеть. Избавляемся от лишних ненужных запросов браузера, которые могут занимать секунды. Для этого реализуем постоянный кэш из localstorage. как наиболее эффективное решение проблемы.


                      1. kahi4
                        29.04.2018 21:09

                        Ну объясните мне, пожалуйста, каким образом Fiddler влазит в политику браузера — посылать запрос к ресурсу ли нет?

                        Вы статью по ссылке читали? Шлет max-age: 0 или типа того. В статье же четко написано — если кеш истёк — браузер спрашивает страницу, если пришёл 304 — рисует из кеша. Не истёк — ничего не спрашивает.


              1. YemSalat
                29.04.2018 16:34

                Мне важны заход на сайт и F5.

                Но по итогу вы оптимизируете только Ф5 (сомнительное занятие, на мой взгляд).
                Только в вашем случае при открытии сайта — вам еще нужно застопарить парсинг на том месте где вы дергаете и проверяете свой скрипт.
                Просто добавьте вашему файлу стилей версию в название файла и поставьте max-age на миллион лет — будет тот же эффект, даже лучше.


  1. Koneru
    29.04.2018 09:29

    А вы проводили замеры скорости загрузки страницы с вашей оптимизацией и без? И после изменения файлов? Просто что то подсказывает что отклик будет выше. Особенно на нормальном интернете.


    1. altrus Автор
      29.04.2018 10:07

      Вы правы, нужно было в самом начале более четко предупредить, что данная тема только для сайтов с пользователями со слабым интернетом. Если у тебя мощный компьютер и толстый канал, о таких вещах можно не задумываться.
      Замеры не делал и не вижу в них необходимости — сайт ощутимо быстрей прорисовывается, потому что нет двух блокирующих запросов к стилям и скриптам в шапке страницы. Запросы за 304 HTTP ответом на слабом интернете занимают секунды. Даже если хорошо настроены временные валидаторы, такие ненужные запросы в определенных случаях будут. В моем варианте — нет.


      1. kahi4
        29.04.2018 10:25

        А может тогда не нужно пихать блокирующие стили и тем более js в шапку? Проблеме сто лет в обед, и лезть внутрь механизма кеширования далеко не лучшая идея.


        1. altrus Автор
          29.04.2018 10:43

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

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

          Может вы объясните?


          1. kahi4
            29.04.2018 11:25

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


            1. Когда у ресурса отдаётся cache policy, браузер не ходит второй раз за ресурсом, иногда это даже создаёт проблемы. В случае с fiddler — у них намеренно настроена политика таким образом, чтобы браузер переспрашивал, потому что отдаваемые ресурсы меняются часто, без этого он бы только засрал и кеш и свои хранилища (файлами с случайным хешем).


            2. Браузер вправе кешировать не сырые данные, а уже AST или даже результат работы JIT, ещё он компилирует и кеширует шаблоны и вообще умён в этом. Хранение в localStorage обходится дорогими операциями изменения DOM и перепарсинга сорцов. Вообще они сперва грузятся в одно место, потом копируются в другое, затем идут в третье и там снова парсятся.


            3. Для первой страницы и первого взаимодействия обычно достаточно крошечных, иногда in-line стилей, js не нужен вообще, его стоит убрать в футер и написать async. Когда первый вид догрузится — может догружать что хочет, пользователь уже видит страницу, но ща первые 3 секунды вряд ли куда будет кликать.


            1. kahi4
              29.04.2018 11:35

              1. Использовать HTTP2, preload и прочее, например Server push.


              2. Первую страницу рендерить на бэке, догружать только куски


              3. Грамотно побить на чанки, убрать лишние зависимости.


              4. Как уже сказали — использовать предназначенные для этого web workers.


              5. Использовать CDN

              Ваш вариант ничем не плох кроме того что это велосипед. Куча народа работает над решением этой проблемы, напридумывали сотни API, а оказалось все так просто — localStorage, который может случайным образом чиститься браузером, когда не хватает памяти, ограниченный по размеру, умеющий хранить только строки, синхронный, не самый быстрый, а ещё не доступный на поддоменах, да и наверное втрое увеличивающий задержку при первом открытии.


              Либо у вас простенький сайт и проще обойтись вообще без js, либо оно очень быстро упрется в ограничения, из-за которых браузеры сбрасывают кеш по f5


              1. altrus Автор
                29.04.2018 11:41

                О, большое спасибо.
                Вы предлагаете мне полностью изменить архитектуру своего сайта, устроив блэкджэк с web workers и шлюхами, хотя я всего лишь спросил, как лучше закэшировать один css файлик.


                1. kahi4
                  29.04.2018 11:54

                  Вам давно ответили, что прописать заголовок Cache-Contoll: maxage=9999999, но вы уперлись в какие-то бредовые отговорки типа «на fiddler ходит с 304» и «браузер игнорирует это поведение при нажатии на f5”, хоть я вам и сказал почему происходит и первое и второе. И пруфы, что отправить заголовок и получить заголовок занимает 3 и более секунды скриншотом в студию. Это даже для GPRS многовато.


                  Но если хотите делать по-уму — я расписал как. В чем претензии?


                  1. altrus Автор
                    29.04.2018 12:02

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


              1. kahi4
                29.04.2018 11:44

                А ещё я уверен, что при достижении такого Кеша 100 кб вкладка начнёт подвисать в момент обновления, а при 500кб вообще валиться с «перестала отвечать».


                1. altrus Автор
                  29.04.2018 11:51

                  В сумме css и js у меня как раз килобайт на 400 — не замечаю ничего подобного.
                  Комп средний, вкладки иногда зависают, но точно не на моем сайте.


                  1. staticlab
                    29.04.2018 21:06

                    А вы не пробовали передавать свои ассеты с сервера сжатыми? Делали ли их минификацию?


                    1. altrus Автор
                      30.04.2018 03:38

                      Любой современный сервер/хостер автоматически использует gzip/deflate.
                      Все нужные ресурсы минифицированы. естественно. Это не относится к теме поста.


            1. altrus Автор
              29.04.2018 11:39

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


          1. Alexmaru
            29.04.2018 12:50

            Ну, благодаря таким сайтам использование страх iPad сейчас почти не возмно. Страница догружается, память забивается, браузер крешится. Чаще это возникает, конечно, от рекламы, но использовать сторейж не по назначению очень жестоко.


            Я использую полную генерацию css и js, каждый раз с уникальным названием файла. Проблем не создаёт.


            1. altrus Автор
              29.04.2018 12:59

              Браузер не может крэшиться из-за того, что в нем где-то лежит пара мегабайт текста. Браузер падает из-за кода, который в нем исполняется.

              Я поздравляю вас и ваших пользователей с хорошим интернет каналам. Моя тема об обратной ситуации.


              1. SanSYS
                29.04.2018 14:46

                Сам лично видел краш сафари на iPad именно при получении нескольких мегабайт текста по xhr (версию устройства не скажу, не разбираюсь в них в нуль)
                Даже не помню, фронт тогда смог что нить с этим сделать или нет, но было забавно очень )


                1. altrus Автор
                  29.04.2018 16:31

                  Есть не то что большая — огромная разница между загрузкой мегабайтного json-а (или не json-а) по xhr, парсинга его и прочей js-програмной мутотени, и считывания 300 кб (у меня) текста из локального хранилища и вставкой его в виде текста же в html страницу для последующего парсинга стандартными средствами браузера.


          1. Koneru
            29.04.2018 13:59

            А что если пользователь намеренно(или нет) изменит скрипт в вашем хранилище? Он будет запускать сайт и у него он будет падать. Или же localstorage переполниться и будут повреждены файлы? Вы проверяете на целостность данных?


            1. altrus Автор
              29.04.2018 14:00
              +1

              Нет.
              Мазохистов и психопатов я не отслеживаю и за их здоровье ответственности не несу. Это написано в Пользовательском соглашении сайта.

              п.с. Попробуйте в своей винде в system32 удалить что-нибудь. И предъявите потом Гейтсу.


              1. Koneru
                29.04.2018 14:44

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


                1. altrus Автор
                  29.04.2018 16:27

                  Уверяю вас, залезть с изменениями в localStorage и удалить что-нибудь важное из system32 — задачи одного уровня сложности. Если кто-то это захочет — он сделает. Хоть сознательно, хоть случайно. Но это тема другого хаба.


      1. Sabubu
        29.04.2018 17:09

        И с резиновым диском. Явно не для телефонов на андроид с 8 Гб внутренней памяти, да?


      1. ookami_kb
        30.04.2018 01:04

        Замеры не делал и не вижу в них необходимости

        Ну это просто классика!


  1. altrus Автор
    29.04.2018 11:36

    -


  1. Raimon
    29.04.2018 14:17

    Если я правильно помню, заголовок max-age позволяет не отправлять запрос, а использовать версию из кэша браузера.


  1. SanSYS
    29.04.2018 14:48

    В целом — спасибо автору, я столько полезных комментов прочёл…


  1. Sabubu
    29.04.2018 16:44

    Вы занимаетесь вредительством. В браузере есть кеш, и с помощью специальных HTTP заголовков (Expires, Cache-control) вы можете сказать браузеру закешировать файл «навсегда». Естественно, кеш не резиновый и файлы других сайтов будут вытеснять ваши.

    Локальное хранилище — другая вещь. Оно для сохранения пользовательских данных. Данные из него не удаляются и само по себе оно не очищается.

    Вы пытаетесь перехитрить систему, но в конечном счете такие действия будут приводить к неудобствам (например, сокращающееся место на диске), а разработчики браузеров сделают диалог подтверждения для использования хранилища.

    Очень жаль, что такие статьи подаются под видом «туториалов». Это пример того, как делать ни в коем случае нельзя. Неграмотность автора поражает — он не только не разбирается в кешировании, но и правильно JS код написать без document.write не может.


  1. bromzh
    29.04.2018 22:49

    А как быть с режимом инкогнито? Сафари (и мобильный и нет) в режиме инкогнито имеют нулевой размер локалстораджа.


    1. altrus Автор
      30.04.2018 03:36

      Никак. Работает с обычным кэшем.


  1. Carburn
    29.04.2018 23:13

    У меня нормальный интернет и с отключенным кэшем все нормально работает.


  1. Scf
    30.04.2018 15:40
    +1

    Для этой цели лучше использовать Service Worker:
    https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API


    1. altrus Автор
      30.04.2018 15:48
      +1

      Спасибо, я уже понял.


  1. Andre_487
    01.05.2018 01:29
    +2

    Мы в Поиске Яндекса тоже когда-то давно догадались до оптимизации путём складывания статики в LocalStorage.


    Для нас это было более актуально, так как мы много инлайним в страницу. Не от хорошей жизни – вариативность страницы большая, и HTTP-кэш практически не работает на кусках статики, которые нужны множеству уникальных блоков.


    Так вот, внедрили кэширование в LS, увидели драматическое уменьшение размера HTML, не смогли увидеть ухудшение в DevTools – обрадовались и стали использовать.


    Шли годы, скорость обрастала аналитикой и прочим А/Б тестированием, и в голову пришла идея перепроверить – примерно на двухтысячном тикете про баги в фиче, где не оттестировали сценарий, когда статика берётся из кэша. Дело близилось к середине 2017, на тот момент мы уже умели получать со всей аудитории скоростной фидбек в виде метрик. У нас были:


    • все стандартные метрики Navigation Timing API
    • время отрисовки шапки (страница отдаётся чанками, и шапка приходит сильно раньше выдачи)
    • начало парсинга выдачи
    • окончание инициализации клиентского фреймворка
    • разработанные другими командами метрики поведения пользователя на странице

    Провели А/Б эксперимент и увидели:


    • +12% времени скачивания HTML – логично, мы же начали передавать по сети то, что раньше не передавали;
    • -3% времени до отрисовки шапки – уже не так логично – мы же оптимизацию отключаем;
    • -1% времи до начала парсинга выдачи, и примерно на столько же – времени до инициализации клиентского фреймворка;
    • уменьшилось время до первого клика по выдаче, что косвенно говорит о том, что выдача раньше отрисовывается и становится доступной пользователю для взаимодействия; позже у нас появились более конкретные метрики на эту тему, но тогда не было.

    После этого кэширование в LS благополучно отключили, а после удаления машинерии по управлению этим кэшированием и множества noscript на случай отключенного JS, увидели на потоке ещё большее ускорение.


    И про ServiceWorker мне есть что рассказать. Как-то раз мы решили его попробовать, и начать не сразу с места в карьер, а с умом и пошагово – сперва снять показания с самой лёгкой вариации. Добавили sw.js, который ничего не умел, кроме как устанавливаться и навешивать пустой обработчик на событие fetch.


    И снова поймали замедление. Сотни миллисекунд по всем метрикам, начиная со времени до первого байта. Так что для кэширования я бы рекомендовал SW только после серьёзного исследования – иначе есть риск сделать всё не правильно, а совсем наоборот. Если попадание в HTTP-кэш хорошее (у нас 80–90%) – будет точно медленнее.


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


    В итоге сейчас мы пришли к следующей схеме:


    • весь CSS инлайновый – так быстрее рисуется; даже если стили в дисковом кэше – так быстрее; даже не пытаемся кэшировать это в браузерных хранилищах – всё равно так останется быстрее;
    • jQuery (да, у нас всё ещё jQuery) и бандл с фреймворком i-bem и общими сущностями загружаются внешними скриптами – с хитрыми префетчами для прокачки кэша;
    • скрипты асинхронны (defer) и расположены в первом чанке HTTP-ответа для WebKit, в остальных – синхронные с предзагрузкой с помощью link[rel=preload] из первого чанка (отключено для FF – там пока баги с preload); это связано с разными нюансами работы разных движков с синхронными и асинхронными скриптами;
    • вычисляем медленные запросы и отправляем на лёгкую версию – там в плане схемы со статикой всё то же самое, но функциональность сильно беднее, и вёрстка сильно хитрее свёрстана – всё с целью уменьшения размера; про это даже есть отдельный пост.

    Можно заметить, что это сильно отличается от рекомендуемого в постах "Как по-быстрому оптимизировать фронденд". И так же как рекомендации из этих постов строго не рекомендуется к применению бездумно.


    Есть, конечно, очевидные вещи, которые можно внедрять не размышляя: вечное кэширование всего, что можно, gzip/brotli для сжатия, скрипты не должны блокировать отрисовку, не нужно сушить кошку в микроволновке. Но в остальном – нужно измерять скорость на реальных пользователях своего сервиса, считать статистику и полагаться на эксперименты. Сервисы разные, пользователи разные – оптимизации подходят разные.


  1. altrus Автор
    01.05.2018 05:55

    Ну, наконец-то, Yandex немного реабилитировал мой подход.
    Вот оказывается кто грузил localStorage пользователей рунета все эти годы, а шишки все на меня )

    По вашим замерам скорости LS и SW, думаю, все дело в интернет-канале. У вас 92 процента быстрых пользователей, на которых кэш+запрос за 304 ответом сравнимы с доступом к LS. Это по пользователям, а по запросам, полагаю, запросы от «бабуль» занимают менее 1% всех обращений. Поэтому для подавляющего числа юзеров прогнать пару пакетов по сети проще, чем, например, запускать SW фреймворк, особенно если браузер перегружен вкладками. отсюда такая статистика.

    У меня 80% пользователей — «мобильщики» на EDGE и перегруженном 3G. Время отклика сети сами понимаете какое. Поэтому в моем случае экономия на двух блокирующих запросах из трех — благо.
    Пост исключительно про мой случай.

    Огромное спасибо за содержательный ответ.