Comments 114
Не проще ли?
Идея автора статьи другая:
- в теле html-файла передать «версию» ресурса
- клиентским JS-ом сравнить «версию» ресурса на сервере и в localStorage
- при совпадении «версии» — взять из localStorage
- при различии «версии» — отправить запрос на сервер
Идея (в теле html-файла перавать «версию» ресурса) — правильная.
А вот использовать для всего остального JS — спорное решение. Навскидку:
- при отключенном JS-е ресурсы не будут загружены вообще
- даже если JS работает, будут сломаны все браузерные оптимизации по предсказанию и предзагрузке ресурсов. В результате может оказаться, что авторская версия, даже не выполняя запросов в сеть, будет медленнее, чем могла бы.
Насчет браузерных оптимизаций не понял. Пример?
<!DOCTYPE html>
<html>
<head>
<link href="css/main.v1.css" rel="stylesheet"/>
</head>
<body>
... BIG_CONTENT ...
</body>
</html>
И продолжая «качать» по сети тело html (считаем, что BIG_CONTENT долго передаётся по сети), он попытается получить валидный «css/main.v1.css».
Если браузер будет уверен в валидности своего кэша — возьмёт из кэша; если не уверен — выполнит запрос (и может оказаться, что данный запрос вернет 304 ещё до окончания докачки тела html).
Существует большая вероятность, что к моменту окончания загрузки html у браузера будут все требуемые ресурсы, и он сможет отрисовать страницу.
<!DOCTYPE html>
<html>
<body>
... BIG_CONTENT ...
<script>
// load "css/main.v1.css"
</script>
</body>
</html>
И даже когда весь html загрузится — не поймёт :)
Браузер должен будет распарсить и выполнить JS.
<!DOCTYPE html>
<html>
<head>
<link href="css/some.v1.css" rel="stylesheet"/>
<script>
// load "css/main.v1.css"
</script>
<link href="css/other.v1.css" rel="stylesheet"/>
</head>
<body>
... BIG_CONTENT ...
</body>
</html>
Для «css/some.v1.css» браузер сможет применить оптимизации из первого примера.
А для «css/other.v1.css» — не сможет, пока не закончит работу JS-loader.
CSS в качестве ресурсов и только в заголовке — это только для примера. Это с таким же успехом может быть и какие-нибудь картинки в дебрях BIG_CONTENT.
А в варианте автора, при несовпадении версий нескольких файлов, вероятна ситуация, когда клиенты сгенерируют гору запросов по каждому отдельно обновлённому компоненту приложения.
Для поклонников стандартного кэша браузеров, гордо показывающих на слово «Кэшировано» в Средствах разработчика, советую открыть Fiddler и увидеть, что по каждому кэшированному ресурсу за 302 HTTP ответом всё равно идет запрос
Во-первых, не 302 («Moved Temporarily»), а 304 («Not Modified»).
Во-вторых, запрос браузером закэшированного ресурса говорит о том, что браузер «сомневается» в актуальности кэшированных данных.
Однако существуют механизмы, «убеждающие» браузер в том, что его кэш не требует ревалидации (cache-control immutable).
Ваша реализация («используется время последнего изменения файла как его «версия»») вполне себе закрывается данным механизмом. Причем будет работать даже при выключенном/заблокированном JS в браузере.
По поводу cache-control immutable — как я понимаю браузерная поддержка пока слабая, особенно для смартфонов.
Попробуйте следить не только за нововведениями, а изучить основы веб-разработки. Про кеширование в HTTP я читал статью еще 10 лет назад, и тогда уже все работало. Как можно об этом не знать, но при этом интересоваться какими-то неработающими технологиями, я удивляюсь.
Там почему-то неправильные данные. Указано, что Chrome не поддерживает, но это не так. Можно убедиться на практике – попробовать отдать этот заголовок на каком-то ресурсе и попробовать нажать Ctrl+R – если он в кэше, и кэш ещё валиден – ресурс не будет скачан.
Уже вполне неплохая. Chromium поддерживает, так же как и Safari. Так что уже можно – мы пользуемся, например
Рассматривали возможности Html5 Application Cache?
Вот тут скрин с фиддлером — style.css запрошен лишь раз
Не знал про Application Cache, честно говоря, спасибо за наводку.
Спасибо, за поправку
Use Service Workers instead
Забавно, а с ними уже столкнулся на вебпушах, но только немного по фану, в прод на жс не пишу давно
Ну пока он работает его можно использовать. А работать он будет скорей всего долго.
При типичном использовании(когда пользователь не касается 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 у вас на сайте, при этом вы не используете «умную загрзуку» необходимых для страницы ресурсов.
2. Это на порядок (порядки) меньше затрат на запрос за 304 ответом
3. и 4. Откройте Fiddler
Очень информативное чтиво по теме браузерного кэша, 304 ответов и прочего от создателей Fiddler:
https://www.telerik.com/blogs/understanding-http-304-responses
А теперь о ремарках
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. Для прочих ресурсов нет.
Во-вторых, у вас вариант когда браузер может то запросить ресурс, то не запросить (про F5 точно выяснили, но наверно есть и другие нюансы браузерной логики, которые гарантировать нельзя). У меня вариант, что он запрашивает ТОЛЬКО ТОГДА, когда ресурс меняется и его надо обновить. Для меня лично выбор очевиден, другим ничего не навязываю. Просто поделился.
В-третьих, вы советуете мах-age поставить. Но у меня сайт развивается, css и js частенько меняются, что делать? Параметр после "?" использовать нельзя, как вы сами сказали, значит нужно менять имя? Некрасиво, как по мне. Да и кэш браузерный захламлять.
Про вкладки не понял. Вы апеллируете, что для каждой вкладки будет запускаться движок локал стораджа с моими 500 кб и это нагрузит систему?
Вот смотрите, у меня сейчас около 20 вкладок открыто, полдня где-то. Я не работаю, просто читаю-пишу в нете. Вот загрузка:
Вы найдете там несчастные 500 кб моих скриптов и стилей?
Про умную загрузку понял. Вы бы о ней Google рассказали с его сайтами)
Я хочу, чтобы при показе первого экрана пользователь сразу мог кликнуть на меню и оно открылось. Чтоб он не кликал и не расстраивался, что оно заработает только через несколько секунд. Для этого надо загрузить JQuery и 70% (по весу) скриптов. Какой смысл разбивать? Нету. Я пробовал, правда. И css и js 30%-70% нужно вверх. Такой сайт и менять его поведение я не буду, потому что оно хорошее. Вместо этого кэш в локал сторадж решает все проблемы. Топор тоже не предназначен гвозди забивать, но прекрасно справляется с этой работой.
Ну так правильно, пользователь просит обновить страницу с сервера, браузер это делает. Так и должно быть.
> У меня вариант, что он запрашивает ТОЛЬКО ТОГДА, когда ресурс меняется и его надо обновить.
Как принудительно обновить страницу с сервера в обход кеша?
> Параметр после "?" использовать нельзя, как вы сами сказали, значит нужно менять имя?
Во-первых, можно, он наверно ошибся, во-вторых, можно менять имя папки: /css/v11/styles.css. Вы бы основы протокола HTTP изучили, глядишь и не пришлось бы кривые велосипеды изобретать.
> Вы апеллируете, что для каждой вкладки будет запускаться движок локал стораджа с моими 500 кб и это нагрузит систему?
Если каждый сайт начнет класть хлам в локалсторадж то да, это конечно приведет к неудобствам и разработчики браузеров понизят лимиты для всех, в том числе и для тех кто его по назначению использует.
> Я хочу, чтобы при показе первого экрана пользователь сразу мог кликнуть на меню и оно открылось.
У вас же блокирующий код с document.write. Почитайте про асинхронную загрузку скриптов на досуге.
> У меня все работает
Тогда не пишите туториалов и не учите других людей неправильным вещам. Если вы беретесь писать статью, изучите хотя бы минимально теорию, а то иначе один неграмотный человек учит других.
2. Браузер что FF что webkit НИКОГДА не запросит даже 304 если ресурс подгружался динамически во второй фазе. Исключение если ресурс грузится с параметром.
3. Да менять имя. И так это и делают все нормальные люди. Меняют имя не руками конечно. Какое в проекте имя и какое отдается в страницу — вопрос организации работы. Кеш так вы не захламите. Браузеры очень оперативно исключают из кеша то, что не используется даже с большим max-ege.
4. по вкладкам, я имел ввиду когда много разных ресурсов начнут активно пользовать большой обьем данных в локалстораже. В результате вы получите ситуацию когда ваша вкладка может висеть и ждать своей очереди.
5. Гугл именно так и работает везде где это возможно. Откройте google.com и посмотри в его внутренности. Подымите свое понимание относительно того, как писать быстрые страницы на новый уровень. А для гугла, каждая миллисикунда стоит больших денег. Кстати в гугловсом Pagespeed тесте этому уделяется очень большое внимание.
6. То что Вам для работы меню нужен JQuery говорит о том, что вы неправильно выбрали инструмент для решения своих проблем. В настоящий момент просто открытие меню со свистоперделками можно писать на чистом CSS без javascript кода вообще. Или с минимальным кодом в несколкьо команд.
Главное.
Вам не только я пытаются сказать, что в вашем материале неверный посыл. Работа через LocalStorasge имеет смысл только в очень специфической ситуации (неспособность правильно выставить заголовки кеширования на веб сервере). Во всех же остальных случаях, работа с кешем бразуера не хуже, а зачастую лучше чем велосипед с LocalStorage, который может еще и вредить производительности.
И коль Вас не убеждают ни мои доводы, и вы не желаете поднять свой сервер чтобы провести тесты, я еще раз призываю вас погуглить эту тему. В сети много лет назад эта тема активно муссировалась с тестами от очень умных бородатых дядек.
У нас с вами просто разное понимание о том, какой должен быть сайт, разные сферы деятельности. Нет общего предмета обсуждения.
Мой текущий предмет деятельности — это миллисекунды которые нужно выиграть чтобы проект работал быстро. И это не зависит от того что перед Вами — сайт или веб приложение. Методы для оптимизации этого едины.
Вы в своей статье даете вредный и чудовищно неправильный посыл.
О чем я еще раз заявляю. И подчеркиваю — ТАК ДЕЛАТЬ НЕЛЬЗЯ.
По моему мнению, в целом данный способ рабочий, но для очень узкого спектра веб-приложений. В основном SPA. Сам использовал и для тех задач, это было норм, но с появлением Service Worker данный велосипед вообще теряет смысл.
Если используете вебпак:
https://github.com/NekR/offline-plugin
https://github.com/oliviertassinari/serviceworker-webpack-plugin
Кукбук, в котором куча примеров
https://serviceworke.rs/strategy-cache-only_index_doc.html
Только я не совсем понял, почему в localStorage не следует хранить свой css, а через Service Workers можно.
Концептуально, кроме синхронности localStorage в чем проблемы?
Понятно, что Service Workers удобней и функциональней, но почему кэшировать пару текстовых файлов в localStorage вредно?
Из очевидных минусов этого подхода, по сравнению с Service Worker:
- Создан как хранилище ключ-значение, а не для кэширования файлов, поэтому может иметь ряд ограничений для этой цели как в настоящем, так и в будущем.
- Имеет синхронный интерфейс и управляется из js, т.е. «вешает» страницу и вообще не работает если вдруг наблюдаются проблемы со скриптами (на мобильном интернете это сплошь и рядом)
- В отличие от Service Worker, который просто прокси, полностью подменяет собой браузерные механизмы загрузки ресурсов, что может быть чревато. Service Worker подключается 3-мя строчкам и ничего не ломает, даже если браузер его вообще не поддерживает.
Из плюсов этого подхода, которые лично мне импонировали 5 лет назад, когда я его использовал:
- Единственный способ нарисовать более-менее «честный» прогресс-бар.
- Единственный способ действительно грузить ресурсы параллельно (обычно 7 потоков) во всех бразуерах начиная с IE 8
Я не призывал пихать в localStorage графику и шрифты. Не говорил, что это универсальное решение. Конкретно по моему случаю — пара текстовых ресурсов, оба в любом случае грузятся блокирующими синхронными запросами (и синхронность localStorage тут естественна — просто один программный поток). localStorage я использую просто как глобальную переменную — он для этого и создан. Сравнивать его по функционалу и предназначению с Service Worker все равно что сравнивать массив строковых переменных и программный фреймворк со своей базой данных.
У меня стояла небольшая локальная задача, я ее решил так. Пользователю это не вредит — если браузер выделяет под это 5 мегабайт, то, наверное, подразумевается, что там не только коротенькие имя-фамилия юзера будут храниться. Поднявшийся антагонизм не понимаю…
Я смотрел Service Worker, мне понравилось. В будущем перейду. Единственное, на самом деле что пока не дает — необходимость https. У многих моих пользователей слабый инет, а я как-то долго сидел на EDGE с максимум несколькими кб в секунду. Так вот на такой скорости разница между http и https дискретная — первый как-то качает, второй — нет.
Вопрос, стоит ли хранить javascript и css ресурсы веб-страницы в LocalStorage браузера или позволить ему самому отрабатывать кэширование, не имеет однозначного ответа
Вообще-то есть, и это однозначно нет.
Для этой задачи есть Cache API или на крайний случай IndexedDB, что вместе с Service Worker является стандартом де-факто в современных приложениях, нацеленных на работу offline.
Cache API экспериментален и не поддерживается в некоторых браузерах, работает только по https — я теряю на нем 95% своих пользователей
IndexedDB сложен и сам по себе, и для этой задачи. Микроскопом заколачивать гвозди
Cache API и правда не поддерживается в старых браузерах. Оставьте их в покое, если обновляться не хотят. Про HTTPS есть Let's Encrypt, так что если вы уважаете ваших пользователей, у вас нет никакого оправдания не включать HTTPS на всех сайтах что под вашим контролем.
IndexedDB сложен, но позволяет хранить бинарные данные в нужных объемах. Аналогия с микроскопом тут ни к чему.
Что за текстовая информация размером в мегабайты?
Неудовлетворительное объяснение.
По https: именно потому, что я уважаю своих пользователей на слабом интернете, никакого https там не предполагается.
Нет, не нахожу. 5МиБ это совсем не много. А если засунете туда пару неизбежно связанных с CSS картинок в base64 и место закончится. Не говоря о том, как неудобно и медленно оттуда синхронно доставать данные.
именно потому, что я уважаю своих пользователей на слабом интернете, никакого https там не предполагается
Ознакомьтесь с HTTP/2. А потом серьезно пересмотрите критерии оценки уважения к пользователям.
Честно говоря, ваши рассуждения выглядят неубедительно, тем более, что они не подкреплены тестами.
До того, как пользователь увидит буковки в открывающейся странице и начнет читать, должно произойти, грубо говоря, 3 запроса:
1. к странице
2. к css файлу
3. к js файлу
Это блокирующие запросы браузера. Я экономлю на 2 запросах из 3. Еще раз, если вы посмотрите время выполнения запросов на pingdom.com, например, то увидите, что пустой запрос за 304 ответом отнимает примерно столько же времени, как и запрос за ресурсом в несколько десятков килобайт. В зависимости от типа сети.
Итого в среднем я выигрываю пускай примерно 50% времени от клика пользователя на ссылку до появления на экране страницы.
Так понятней?
Дело не в объеме скачанной информации, а времени появления страницы. Три запроса.
Вы написали что картинки у вас lazy load. Это когда заходишь на сайт, начинаешь прокрутку и наслаждаешься как колбасит страницу от появляющихся изображений? Да, и это все ради мегабайта-двух?
Размер шрифта заголовка вычисляется заранее таким образом, чтобы заголовок не занимал больше 50% площади картинки.
Если пользователь прокручивает экран неспеша (со скоростью чтения) картинка успевает загрузиться и вставиться до момента появления ее в видимой части экрана.
Вот так это работает. Мне нравится.
Причем тут «мегабайта-двух» не понял.
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
А может быть наоборот игнорирование кеша по f5 фича, а не баг?
Игнорирование Кеша сделано намеренно, на случай, если в кеш попало что-то, что не должно было. В вашем варианте такого решения нет (нажать ctrl+shift+r знают и умеют многие, чистить localstorage — я бы тоже не допер)
Вы в папку temp винды часто лазите чистить, или в реестровые ветки различных программ? А в localstorage вам зачем лазить без особой надобности?
Я констатирую факт, что из-за этого у пользователей моего сайта будут лаги при прорисовке браузером страниц.
Только если они жмут Ф5 (что, кстати, обосновывает проверку локального кэша через отправку ХЭД запросов) при обычном переходе по ссылкам фаерфокс для закэшированных ресурсов сеть дергать не будет.
Я так и не могу четко услышать «минусы» моего подхода, кроме «локальное хранилище для этого не предназначено».
«Минусы» кэша браузера есть — бесполезные походы за 304 ответом. А «минусы» кастомного кэша в локальном хранилище?
Помните, я говорил, что localstorage чистится в случайное время? Так вот, он не чистится. В итоге если пользователь хоть раз зашёл и ушёл навсегда — ваши данные будут впустую захламлять ему место. К счастью, от этого решения 5 лет назад все отказались и забыли о нем.
Ещё недостаток — мне было бы неприятно, если бы моя страница фризилась на пол секунды. А ещё веб воркер гораздо лучше подходит — клиент не будет вообще ни за какими данными кроме небольшого json с текстом ходить и работать будет мгновенно.
Это единственный «минус»?
Вебворкер, наверное, действительно лучше подходит, поизучаю (для шрифтов и картинок). Но по эффективности мой метод предпочтительней. хотя бы потому. что он уже работает.
Знаете, у меня этот сайт был поначалу в виде андроидного приложения с вашими json запросами. А потом я перешел полностью на сайт, потому что это удобней и мне и пользователям. В сайт можно встроить ту же логику с нынешними технологиями, что и в приложение.
Вообще тут великолепно описано что и как. И самый простой и эффективный и правильный способ — Cache Control. И никаких там 304 не бывает (если ресурс еще не expired). И никаких лишних запросов. Повторюсь, в Fiddler это сделано намеренно (им проще с 304 жить).
Полагаю, мои 400 кб данных не сильно утяжелят его терабайтный диск с кучей реально ненужного хлама )
Вообще не сочтите за наезд, но 400 кб данных у пользователей с терабайтными дисками и жаловаться на скорость загрузки — я представить себе такую задачу не могу. Либо у пользователь мобильные телефоны с GPRS и надо бы переделать с 400кб на не более ста, сперва, да и вообще чем больше отдаст сервер уже зарендеренного, тем лучше, либо проблема высосана из пальца и решается политиками кеша и CDN. (А еще один сайт 400кб, второй, а через месяц вникуда отожраны пару ГБ. У меня, например, на походном ноуте 128 гб памяти, а не терабайты и я там подсчитываю кто обнаглел).
- Service workers, не web workers, попутал немного.
Повторюсь, в Fiddler это сделано намеренно (им проще с 304 жить).
Ну объясните мне, пожалуйста, каким образом Fiddler влазит в политику браузера — посылать запрос к ресурсу ли нет?
У пользователей средние телефоны, средние компьютеры, и плохая сеть. Провинция, ничего необычного. Ключевое слово — плохая сеть. Избавляемся от лишних ненужных запросов браузера, которые могут занимать секунды. Для этого реализуем постоянный кэш из localstorage. как наиболее эффективное решение проблемы.
Ну объясните мне, пожалуйста, каким образом Fiddler влазит в политику браузера — посылать запрос к ресурсу ли нет?
Вы статью по ссылке читали? Шлет max-age: 0 или типа того. В статье же четко написано — если кеш истёк — браузер спрашивает страницу, если пришёл 304 — рисует из кеша. Не истёк — ничего не спрашивает.
Мне важны заход на сайт и F5.
Но по итогу вы оптимизируете только Ф5 (сомнительное занятие, на мой взгляд).
Только в вашем случае при открытии сайта — вам еще нужно застопарить парсинг на том месте где вы дергаете и проверяете свой скрипт.
Просто добавьте вашему файлу стилей версию в название файла и поставьте max-age на миллион лет — будет тот же эффект, даже лучше.
Замеры не делал и не вижу в них необходимости — сайт ощутимо быстрей прорисовывается, потому что нет двух блокирующих запросов к стилям и скриптам в шапке страницы. Запросы за 304 HTTP ответом на слабом интернете занимают секунды. Даже если хорошо настроены временные валидаторы, такие ненужные запросы в определенных случаях будут. В моем варианте — нет.
А может тогда не нужно пихать блокирующие стили и тем более js в шапку? Проблеме сто лет в обед, и лезть внутрь механизма кеширования далеко не лучшая идея.
Пока что я слышу здесь много возражений, что так не надо делать, но никто не объясняет, почему так не надо делать, и как сделать лучше в моем случае (слабый инет).
Может вы объясните?
Давайте на чистоту. Если бы все было так просто, браузер бы внутри работал так же. Но у него другая логика, значит на это есть причины.
Когда у ресурса отдаётся cache policy, браузер не ходит второй раз за ресурсом, иногда это даже создаёт проблемы. В случае с fiddler — у них намеренно настроена политика таким образом, чтобы браузер переспрашивал, потому что отдаваемые ресурсы меняются часто, без этого он бы только засрал и кеш и свои хранилища (файлами с случайным хешем).
Браузер вправе кешировать не сырые данные, а уже AST или даже результат работы JIT, ещё он компилирует и кеширует шаблоны и вообще умён в этом. Хранение в localStorage обходится дорогими операциями изменения DOM и перепарсинга сорцов. Вообще они сперва грузятся в одно место, потом копируются в другое, затем идут в третье и там снова парсятся.
- Для первой страницы и первого взаимодействия обычно достаточно крошечных, иногда in-line стилей, js не нужен вообще, его стоит убрать в футер и написать async. Когда первый вид догрузится — может догружать что хочет, пользователь уже видит страницу, но ща первые 3 секунды вряд ли куда будет кликать.
Использовать HTTP2, preload и прочее, например Server push.
Первую страницу рендерить на бэке, догружать только куски
Грамотно побить на чанки, убрать лишние зависимости.
Как уже сказали — использовать предназначенные для этого web workers.
- Использовать CDN
Ваш вариант ничем не плох кроме того что это велосипед. Куча народа работает над решением этой проблемы, напридумывали сотни API, а оказалось все так просто — localStorage, который может случайным образом чиститься браузером, когда не хватает памяти, ограниченный по размеру, умеющий хранить только строки, синхронный, не самый быстрый, а ещё не доступный на поддоменах, да и наверное втрое увеличивающий задержку при первом открытии.
Либо у вас простенький сайт и проще обойтись вообще без js, либо оно очень быстро упрется в ограничения, из-за которых браузеры сбрасывают кеш по f5
Вы предлагаете мне полностью изменить архитектуру своего сайта, устроив блэкджэк с web workers и шлюхами, хотя я всего лишь спросил, как лучше закэшировать один css файлик.
Вам давно ответили, что прописать заголовок Cache-Contoll: maxage=9999999, но вы уперлись в какие-то бредовые отговорки типа «на fiddler ходит с 304» и «браузер игнорирует это поведение при нажатии на f5”, хоть я вам и сказал почему происходит и первое и второе. И пруфы, что отправить заголовок и получить заголовок занимает 3 и более секунды скриншотом в студию. Это даже для GPRS многовато.
Но если хотите делать по-уму — я расписал как. В чем претензии?
А ещё я уверен, что при достижении такого Кеша 100 кб вкладка начнёт подвисать в момент обновления, а при 500кб вообще валиться с «перестала отвечать».
Комп средний, вкладки иногда зависают, но точно не на моем сайте.
Я сужу с точки зрения обывателя. пялящегося в экран своего смартфона
Я поздравляю вас и ваших пользователей с хорошим интернет каналам. Моя тема об обратной ситуации.
Даже не помню, фронт тогда смог что нить с этим сделать или нет, но было забавно очень )
Мазохистов и психопатов я не отслеживаю и за их здоровье ответственности не несу. Это написано в Пользовательском соглашении сайта.
п.с. Попробуйте в своей винде в system32 удалить что-нибудь. И предъявите потом Гейтсу.
Замеры не делал и не вижу в них необходимости
Ну это просто классика!
Локальное хранилище — другая вещь. Оно для сохранения пользовательских данных. Данные из него не удаляются и само по себе оно не очищается.
Вы пытаетесь перехитрить систему, но в конечном счете такие действия будут приводить к неудобствам (например, сокращающееся место на диске), а разработчики браузеров сделают диалог подтверждения для использования хранилища.
Очень жаль, что такие статьи подаются под видом «туториалов». Это пример того, как делать ни в коем случае нельзя. Неграмотность автора поражает — он не только не разбирается в кешировании, но и правильно JS код написать без document.write не может.
А как быть с режимом инкогнито? Сафари (и мобильный и нет) в режиме инкогнито имеют нулевой размер локалстораджа.
Для этой цели лучше использовать Service Worker:
https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
Мы в Поиске Яндекса тоже когда-то давно догадались до оптимизации путём складывания статики в 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 для сжатия, скрипты не должны блокировать отрисовку, не нужно сушить кошку в микроволновке. Но в остальном – нужно измерять скорость на реальных пользователях своего сервиса, считать статистику и полагаться на эксперименты. Сервисы разные, пользователи разные – оптимизации подходят разные.
Вот оказывается кто грузил localStorage пользователей рунета все эти годы, а шишки все на меня )
По вашим замерам скорости LS и SW, думаю, все дело в интернет-канале. У вас 92 процента быстрых пользователей, на которых кэш+запрос за 304 ответом сравнимы с доступом к LS. Это по пользователям, а по запросам, полагаю, запросы от «бабуль» занимают менее 1% всех обращений. Поэтому для подавляющего числа юзеров прогнать пару пакетов по сети проще, чем, например, запускать SW фреймворк, особенно если браузер перегружен вкладками. отсюда такая статистика.
У меня 80% пользователей — «мобильщики» на EDGE и перегруженном 3G. Время отклика сети сами понимаете какое. Поэтому в моем случае экономия на двух блокирующих запросах из трех — благо.
Пост исключительно про мой случай.
Огромное спасибо за содержательный ответ.
И не важно что LocalStorage типа «не для этого» — JavaScript вообще сам по себе не для этого создавался, чем сейчас есть.
Практика — критерий, как верно отметил Andre_487
Но в остальном – нужно измерять скорость на реальных пользователях своего сервиса, считать статистику и полагаться на эксперименты.
К сожалению не так всё хорошо ) Процент медленных запросов на мобильных сетях не превосходит 10%, но достаточно близок. Это примерно и есть доля Бабули.
Учитывая наш опыт, я бы всё-таки рекомендовал попробовать вместо кэширования в LS сжатие в brotli и вечное кэширование в HTTP-кэше для преодоления проблем сети:
Cache-Control: max-age=315360000, public, immutable
В этом случае получится файл меньшего размера, и браузер ни при каких обстоятельствах не будет ходить за 304-м ответом. Остался какой-то процент не поддерживающих immutable, но это может быть проблемой только если высок процент навигаций через refresh.
Статистику о типе навигации можно собрать через Navigation Timing API, свойство performance.navigation.type
.
Сохранение JS и CSS ресурсов в Локальном хранилище браузера