Comments 38
Несколько раз пытался разобраться с этими самыми SW, но все не хватало времени. А теперь все вопросы отпали, пойду прикручивать в паре мест.
Использую гугловский github.com/GoogleChrome/sw-toolbox и .networkFirst политику кэширования.

Остальные на первый взгляд сладкие варианты кэширования как то .cacheFirst чреваты и требуют многодневного тестирования, и что важно, сложного обслуживания/поддержки.
Не могу не добавить свои рассуждения по SW:
  1. Поддержка браузеров!

  2. При использовании SW как прокси мы получаем довольно не плохую задержку в загрузке (-5% -5% +25%)
  3. Пуши — почему то многие о них умалчивают когда говорят о SW а тем не менее это довольно крутая штука.

Как по мне, так использовать SW нужно очень обдуманно. Потому что базовые операции по кешированию отлично могут выполнить заголовки файлов. Отдал заголовок с кешем на месяц, и файл будет браться из кеша браузера. Выкатил новую версию файла, дописал v=number в url. Где здесь SW?
С оффлайном да, хорошая идея, но опять же много чего в оффлайн не засунешь.
1. Про поддержку браузеров.
Как я знаю поддержка в таких браузерах как Safari или Edge находится в разработке.
Поэтому данная технология довольно-таки перспективна на мой взгляд.
Ровно как и часть крупных приложений уже начинают использовать их на проде (twitter, tinder, pinterest, smashingmagazine).

2 и 3
-5% -5% +25% — как сказал Артём Белов: “… сначала забирает, а потом добавляет с лихвой...”
По поводу прокси, пушей и как настроить общение между воркером и веб-страницей ещё будет статья. Тут идея была расписать базовые стратегии для кэширования и как их использовать, по сути “на пальцах“.

Касательно, выставить заголовки и т.п.
Базовые средства оптимизации никто не отменяет)
Кешировать надо все, что только возможно (с умом естественно), просто SW может помочь сделать приложение более отзывчивым и ускорить его отображение пользователю.

По поводу оффлайна:
А всё ли надо засовывать в оффлайн? На мой взгляд нужно лишь класть критичные файлы (css, js, html) и правильно обрабатывать ситуацию, когда нет доступа к сети, оставляя пользователя в приложении, а не заставляя его ждать минуту и в итоге показать Динозаврика.
Статья задумывалась начальной в серии статей о SW API. Хочется понять, насколько тема интересна и полезна. Жду ваших комментариев и пожеланий.

В общем, продолжайте!
Спасибо большое)))
Как говориться, подписывайтесь, ставьте лайки и комментируйте)))

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

Отдать закешированный ответ, а в фоне скачать новый для следующего запроса.

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

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

Но бывают же и изменения, которые надо юзеру сразу доставить (например, старая версия кода несовместима с новой разметкой, которую генерит CMS, или с новым API).
Как отличать эти "важные" изменения от "неважных", чтобы SW отдавал закэшированную версию в одном случае, но не в другом?


И еще такой момент. В реальном приложении нельзя полагаться исключительно на SW — так как есть неподдерживающие его браузеры. Значит, у вас уже предусмотрена система кэширования с возможностью инвалидации кэша при новых релизах. Например, добавляем параметр ?v=< version> к url ресурсов. Или, согласно рекомендации от webpack, дописываем хэш файла, посчитанный при сборке.
В результате при изменении кода URL меняется — и SW не найдет измененный файл в своем кэше.


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

SW это программа, которую вы пишете, а не фиксированная модификация поведения. Вы можете запрогарммировать его как хотите. Поэтому
В результате при изменении кода URL меняется — и SW не найдет измененный файл в своем кэше.
только если вы так запрограммируете. Срезайте ?v=3 в обработчике запроса в коде SW, например.
Как отличать эти «важные» изменения от «неважных
Тут аналогичный ответ — вы пишете код, так что как хотите. Добавьте параметр &major-version=3 например.

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


Наиболее осмысленное применение кэша в SW из примеров, которые я видел в интернете: пре-кэшинг файлов в связке с HTTP/2 Server Push — для решения проблемы с кэшем, присущей Server Push (например, тут).

В случае кэширования в cacheStorage (не обязательно в service-worker, оно доступно и для window) при отправке запроса на серв не нужно получать заголовок — можно перехватить, проверить на какой ресурс запрос, и отдать соответствующий response из cacheStorage. И все это локально. На клиенте. Потому что раньше предусмотрительно положили туда нужные пары request-respones. Поэтому если клиент оффлайн, pwa'шка может отдавать соответствующий response без обращения к серверу. В этом и суть оффлайн pwa. Запросы не уходят в сеть. А чтобы получить заголовок кэширования обычными методами серва, нужна сеть.
А чтобы получить заголовок кэширования обычными методами серва, нужна сеть.

Неправда. Если файл уже закэширован браузером после первого запроса, то последующие запросы к нему выполняются без сети. Я имею в виду безусловное кэширование типа Cache-Control:max-age=<много-много секунд> (в отличие от условного кэширования с ETag/If-Modified-Since).


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

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

Ключевое здесь файл. Статика. В случае кэширования в cacheStorage можно положить text/html response. При чем положить заранее, при первом обращении к серверу. При чем respone на любой request.url. То есть фактически при первом обращении задать список доступных оффлайн страниц.
В случае кэширования в cacheStorage можно положить text/html response

Да, про такой сценарий я не подумал. Обычно саму страницу никто "жестко" (с Cache-Control: max-age) кэшировать не станет. В этом случае SW позволит сделать фоллбэк на оффлайн-режим при отсутствии сети.
Хотя лично мне кажется, что оффлайн режим имеет очень ограниченную область применения. Имхо, не так много реальных приложений, в которых можно сделать что-то осмысленное без сети (типа написания черновика письма в gmail).


То есть фактически при первом обращении задать список доступных оффлайн страниц.

Ясно, pre-caching. Причем, "доступных оффлайн" — здесь даже необязательная часть. Сама страница может требовать сети для работы, но мы все еще можем заранее для нее что-то подгрузить.

Обычно саму страницу никто «жестко» (с Cache-Control: max-age) кэшировать не станет
Зависит от сценария, который реализуется. Как правило при первом обращении кэшируется вся статика необходимая для работы сайта/приложения и какой-то список страниц: rg.ru последние N новостей и показывает плашку «Ой! У вас нет интернета.», видел магазин который клал в кэш сразу все инфо страницы, сайт рекламного агентства — страницы оферов и их описаний.
Почему-то про сервис-воркеры пишут только в контексте кэша и работы оффлайн.

Использую для выполнения фоновых операций, +push уведомления юзерам о статусе этих операций и возможном прекращении их выполнения(если видно что закрыты все вкладки).
Как результат например общая для всех вкладок область видимости/«глобальная асинхронность», то есть если юзер открыл сервис в нескольких вкладках он не может запустить занового идентичный процесс, т.к. этот процесс идет в едином сервис-воркере.

Да, в курсе про такие операции)
Это очень классная вещь)
Я хотел начать с базовых вещей, а далее, в последующих статьях хочется погрузиться в те же пуши, фоновые операции и в другие интересные вещи)
Простите, я возможно отстал от жизни, но неужели SW стал по настоящему доступен на всех устройствах, помнится пол года назад с ним были явные проблемы на устройствах Apple.
Нужна статья о синхронизации и фоновом обновления кэша. Например когда используется cacheFirst и кэшируется вообще все. Статику понятно, можно версионированием кэшей контролировать, а вот с контентом пока только костыли использовал. Например пользователь из листинга ушел в карточку товара, там добавил его в корзину, возвращается на листинг, а ему отдает версия страницы из кэша в которой корзина пустая. Делал для этого historyArr[] в котором хранил все request.url и при определенном запросе на сервер обновлял contentCache чтобы контент всегда был актуальный, но так как немношк не разраб, чувствую что костыль не оч верный и есть нативная синхронизация для подобных вещей.
как я понимаю из вашего контекста, данная задача мало связана с SW.
Если мы говорим о SPA, то подобную задачу можно решить через тот же redux и управлением данными через store, то есть вы сами контролируете, какой листинг вы открыли и если есть данные в store, то запрос можно не делать, а брать данные прямиком из хранилища.
А можно просто настроить заголовки на сервере так, чтобы кэшировать статику и html, но не кэшировать JSON, а все данные заполнять через JS, подтягивая их через этот самый JSON? Зачем тут redux вообще.

Да, я понимаю, что сайт сломается, если отключить JavaScript, плюс могут быть микро-задержки на клиентский рендеринг — но проблему с кэшированием это ведь решит?
Настройка заголовков и кеша не спасает медленной скорости интернета.
Клиент будет делать запрос на сервер и ждать, когда загрузиться html и всё остальное.
В SW иначе, первым делом достаются данные из кеша SW, а потом остальное Тем самым время Time to Interactive сводится к минимуму, т.к. не зависит от сети.
Как итог показываем, что приложение работает, но проблема ответа в скорости сети (так себя ведут мобильные приложения)
Нет, не SPA, обычное PWA которое прикручивается к обычному интернет-магазину с обычным php на бэкенде. Контент в SW делится на imgCache, staticCache и contentCache.

Во время сёрфинга по сайту в contentCache пишется text/html и соответственно при cacheFirst отдается из кэша. Так вот именно его нужно обновлять при определенных действиях: добавили в корзину, удалил, добавил в избранное, к сравнению, лайк\дизлайк, оставил комментарий. Потому что он хранит контент до этих действий. Надеюсь так понятнее :)

И вот такой костыль решает задачу, но чувствую что есть нативное решение.
function updateCacheByName (cacheName,updateRequestsArray) {
caches.delete(cacheName)
.then(function(){
console.log('удалили кэш '+cacheName+' чтобы обновить');
caches.open(cacheName).then(cache => {
return cache.addAll(updateRequestsArray).then(function(){
console.log('история обновлена в кэше '+cacheName);
}).catch( err => {console.log(err);});
});
}).catch( err => {console.log(err);});
}
Я ответил Вам в личку, чтобы не понижать контекст статьи и в целом ее обсуждения)

Мне нравятся статьи, в которых последовательно наращивается уровень материала.


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


В общем, я за продолжение.

UFO landed and left these words here
UFO landed and left these words here
Недавно, один популярный web-сервис внедрил подход «offline first» (или как он там правильно называется). Так вот, однажды при использовании я не сразу заметил, что интернета нет, и продолжал пользоваться сервисом. При этом, несколько раз ловил дикий «ux confusing», если можно так выразится. И только потом заметил маленькую системную надпись от браузера (рядом с протоколом в адресной строке) — типа «сайт offline», или как-то так. Я был несколько расстроен, потому что понял что терял время и контент был невалидный, а взаимодействие фейковое. Ещё подумал про себя — «началось, начали тестить продвинутое кеширование и сервис-воркеры». Так это я разобрался, а что говорить про людей далёких от web-разработки.

Поэтому:
Существует проблема, когда браузер по умолчанию выдаёт вам сообщение о том, что вы офлайн

как по мне, так это не проблема, а вполне понятное, чёткое и однозначное информирование о том что интернета пока нет, займись чем-то другим!
Моё мнение, что для сервисов, где есть плотное взаимодействие с пользователем, или контентных сервисов — подход «offline first» неудачный. Он годится лишь для чисто клиентских самодостаточных приложений (типа как тот гудящий горн на google developers, который приводят везде в пример)

p.s. хотя подозреваю, я тут напутал и намешал с pwa..))
Тут на самом деле понамешано малость.
Да, PWA это про SW, но SW — это не про PWA.

> как по мне, так это не проблема, а вполне понятное, чёткое и однозначное информирование о том что интернета пока нет, займись чем-то другим!

Как я вижу в плане дизайна приложения был допущена ошибка, что пользователь явно не показал, что вы в Offline. По мне это решается довольно просто:
window.addEventListener('offline', () => showOfflineBar());

Это уже проблема приложения, а не SW. Как я выше писал в своей статье, наша задача не просто не показывать «динозаврика», а показать своего «динозаврика» в стиле нашего приложения и была «наша» кнопка «обновить».
Уточните пожалуйста, разве XHR стали синхронными по умолчанию? Также интересно узнать, какая проблема обернуть синхронный вызов localStorage в колбеки, промисы, генераторы – на выбор? Но прежде чем оборачивать вызов localStorage в асинхронный вызов, я бы хотел понять, зачем? Если максимальный размер хранилища 5Мб, то сколько же по вашему мнению будет извлечение этого объёма из оперативы в синхронном режиме? Наберется ли там хотя бы микросекунда?

Одним словом, вы не спутали здесь синхронное исполнение кода и вызов, блокирующий процесс?

Я ничего против воркеров и сервис-воркеров не имею, просто почему синхронность стала проблемой?
Сама технология хороша, но с чего Вы решили, что Ваш сайт достоин кеширования у меня на компьютере? Сейчас это 1-2 сайта, потом 100+, зачем мне 5000+ мб шлака, да ещё синхронизирующегося… Не говоря уже о том, что SW жрут батарейку. Меня уже порядком достали сайты, которые хотят присылать мне уведомления или определить местоположения, хотя я к ним зашёл первый раз по ошибке гугла…
Only those users with full accounts are able to leave comments. Log in, please.
Information
Founded

25 May 1999

Location

Россия

Website

2gis.ru

Employees

1,001–5,000 employees

Registered

9 August 2008

Habr blog