Как часто, запрашивая страницу, мы видим сообщение «Нет подключения к интернету». Однако, уже давно существует возможность отлавливать события в отсутствие интернета и контролировать содержимое, которое видит пользователь. Алексей Чернышев и Максим Чагин запустили offline-версию сайта Российской Газеты – официального издания Правительства России с 1 млн посетителей в сутки – и поделились своим опытом на РИТ++ 2017. Под катом расшифровка их доклада.
Давайте представим – у нас сервис доставки пиццы. Клиент заходит, но у него нет интернета. Он ждет 20 секунд и видит все то же самое: «Нет подключения к интернету». Не думаю, что это остановит его от заказа, если у нас действительно вкусная пицца.
Но вы уверены, что для того, чтобы зайти на сайт, выбрать пиццу, наполнить ее ингредиентами, отправить форму заказа, нам действительно нужен интернет? Да нет, конечно! Все это можно сделать и офлайн, а когда появится соединение, отправить заказ уже на сервер для обработки.
Если интернет так и не появился, можно отправить нотификацию: «Ой! Свяжись с менеджером по телефону или останешься голодным!» Вариант, конечно не идеальный, но лучше, чем ничего.
Это может быть абсолютно любой кейс. Если у вас интернет-магазин, можно пользователю сообщить о распродаже. В случае информационного контента, можно дать почитать интересные материалы.
Вся работа в офлайн строится на использовании Service Worker. У него есть много свойств, но мы поговорим только об основных базовых частях, которые помогут понять, что вообще происходит с офлайном.
Итак, Service Worker – это событийно-управляемый воркер, который получает в себя JavaScript файл, выполняет его, и позволяет:
? Контролировать страницы, в контексте которых это Service Worker был вызван;
? Перехватывать различные запросы и модифицировать их на подконтрольных страницах;
? Кэшировать ресурсы через специальное кэш API.
Также хочется отметить, что он работает в потоке, параллельном от основного, и соответственно, ему не доступен DOM, LocalStorage или объект Window. Но зато он, выполняя какие-то действия, не блокирует основной UI браузера.
Чтобы Service Workerв принципе мог заработать на сайте, и вся магия смогла действовать, его нужно зарегистрировать, потом он должен пройти этап установки и этап активации.
На клиенте нужно вызвать код, который передает путь до нашего Service Worker. Еслиэтот файл доступен и его можно выполнить без ошибок, тогда Service Worker считается зарегистрированным, и начинает прослушивать и просматривать те страницы, которые находятся в его области видимости.
Первое событие, которое возникает – это событие установки. Обрабатывая это событие, мы кэшируем ресурсы, которые впоследствии будем использовать для отдачи клиенту офлайн-версии, через кэш API в браузер.
После этого срабатывает событие активации. Заметим, если Service Worker только в первый раз регистрируется и активируется на странице, то после этого сразу срабатывает событие активации и можно что-то сделать, обрабатывая это событие.
При обновлении Service Worker’а порядок активации отличается. Если до этого на сайте уже была какая-то его версия, а мы изменили файл, браузер, который примерно через сутки проверяет идентичность, понимает: «Ага, у меня новая версия Service Worker лежит на сайте, давайте-ка я ее обновлю!»
После этого в новом Service Worker’е запускается регистрация и установка. Но, если у пользователя открыты страницы со старым Service Worker’ом, новый Service Worker переходит в режим ожидания. Только после того, как они будут закрыты, срабатывает событие активации, и он может продолжать работать, в этот момент можно прибраться за старым Service Worker’ом и удалить ненужные данные.
После того, как мы обработали активацию, Service Worker начинает работать в полную силу, а именно ему доступны следующие события:
Теперь, когда мы знаем, что такое Service Worker и что с его помощью можно управлять кэшом, выделим основные стратегии построения офлайн-приложения.
Берем вообще все, что есть на странице – HTML. CSS, JS, Fonts, SVG, IMG и закидываем в кэш. Это самый простой и быстрый способ сделать ваше приложение доступным в офлайн, но у него есть существенный недостаток. Он подходит для редко обновляемого статического контента, если информация меняется чаще, чем пользователь заходит на сайт, то возможно она попросту утратит свою актуальность и станет никому не нужна.
Такой вариант можно применить для кэширования расписания конференции. У нас уже есть докладчики, все собрано и скомпилировано – закинули в кэш, и все счастливы.
Это способ создания приложения, где подключение к интернету является своего рода усовершенствованием, а не необходимостью. По умолчанию мы считаем, что интернета у нас нет. Вся серверная логика переносится на клиент.
Как только появляется интернет, клиентская часть синхронизируется при необходимости с серверной, а пользователь продолжает работу, как ни в чем не бывало.
Например, у нас есть сервис публикации новостей, редактор может там писать и делать, что угодно, без интернета, а когда интернет появится, все синхронизируется с сервером, и можно будет выводить контент на сайт.
Это развертывание мини-приложения со своей структурой, адресацией, дизайном. Как мы уже говорили, в таком мини-приложении мы перехватываем запрос от пользователя, и в случае, если у него нет интернета, выставляем какой-то контент.
Это может быть все, что угодно – игра, интерактив, опрос. Такой вариант не подходит для сервисов в силу того, что у нас фактически происходит подмена контента, но для информационного, развлекательного ресурса это идеальный вариант.
У себя мы используем именно его расскажем о нем чуть подробнее.
Итак, на конференции Moscow JS коллеги из Лента.ру рассказали, что ни предлагают поиграть в крестики-нолики, если в процессе чтения приложения у пользователя пропадает интернет. Сама идея нам показалась интересной, но одной игрушки мало. Мы рассудили, что пользователь видит все то же сообщение и это банально.
Другой вариант: пользователь заходит на сайт и, пока у него нет интернета, ему предлагают почитать статьи. Это уже лучше – по крайней мере, есть шанс, что мы завладели вниманием пользователя, и после того, как у него появится интернет, он продолжит читать дальше на основном сайте.
Первое, что приходит в голову, когда пытаешься представить себе офлайн-приложение, это 2 страничный SPA: главная страница со списком новостей, и можно открыть любую для прочтения.
Важный вопрос — как сообщить пользователю, что у него открылась офлайн-версия, чтобы он не подумал, что сайт теперь так выглядит. Мы пробовали много разных вариантов, но остановились на простой максимально заметной плашке сверху, которая сообщает, что это офлайн -версия и тут нет рекламы. В правом верхнем углу есть индикатор красного цвета, на котором написано «Offline», как только интернет появляется, он становится зеленым, сигнализируя о том, что доступна целевая страница.
Надо заметить, что в офлайн попадают не все материалы подряд. Это связано со спецификой информационного контента. Представьте, приложение может быть открыто и через неделю, и через месяц после последнего посещения, а мы в июне-июле покажем пользователю что-то вроде «20 мая в Москве потеплеет до климатической нормы». С другой стороны, советы, как сохранить здоровье после 25, всегда актуальны.
Для того, чтобы это все сработало, необходимо хотя бы раз зайти на сайт. После входа на сайт инициализируется Service Worker, добавив в кэш всю необходимую информацию.
Пользователь заходит на сайт и на клиентской стороне страницы включается регистрация Service Worker’а, мы отдаем пользователю в кэш несколько файлов для офлайн-версии, а после этого удаляем ненужное старое.
Далее начинаем проверять доступность самой страницы через события Fetch. А именно, обрабатывая событие Fetch, мы смотрим, если запрашиваемый ресурс доступен, то мы его просто отдаем. Если же нет, уходим в исключение и отдаем через кэш API нашу офлайн-версию.
Пока Service Worker все проверяет и обрабатывает, мы параллельно выясняем, нужно ли обновить данные для офлайн-версии пользователю.
Как уже было сказано, офлайн-версия – это SPA приложение, построенное по стандартной MVC архитектуре: есть контроллер, который получает в нашем случае всего 2 адреса, главной страницы или страницы статьи. Мы забираем данные из кэша и нужный нам кусочек шаблона и отдаем пользователю уже готовую HTML.
Кстати, здесь мы не используем никакие библиотеки типа React или Angular. У нас только шаблонизатор Mustache и обычный JavaScript – просто, чтобы все это не перетаскивать пользователю в браузер.
Теперь нужно решить, как узнать, что интернет появился. События ONONLINE и ONOFFLINE, к сожалению, не подходят, потому что возникают, когда из сетевой карты выдергивается сетевой шнур. И мы пошли в лоб, и это оказалось эффективно.
Через определенный интервал времени внутри приложения отправляется статистика в Google Analytics – если статистика отправилась, мы понимаем, что интернет появился и сообщаем об этом пользователю.
Когда мы разрабатывали эту версию и запускали ее на продакшн, мы столкнулись с рядом проблем, которыми хотим с вами поделиться, чтобы вы не наступили те же грабли.
Первое, что приходит в голову, конечно же, setinterval внутри Service Worker’а – почему бы и нет? Мы провели небольшой эксперимент. Внутри Service Worker’а написали функцию, которая в цикле каждые 10 секунд отправляла простой get запрос на сервер, все данные логировались. После этого заходим на тестовую страницу, чтобы Service Worker инициализировался, закрываем вкладку и ждем, пока Service Worker умрет.
Выяснилось следующее:
В принципе, с setinterval можно работать. Но мы не стали его использовать:
Поэтому мы, как и с проверкой на доступность сети, решили пойти обходным путем. Если пользователь заходит на страницу, когда есть интернет:
Таким образом вычисляется, сколько времени прошло с последнего посещения нашего сайта, и если больше 15 минут, в Service Worker отправляется запрос: «Дружище, пора бы удалить из кэша старые данные и записать туда новые!»
В документации написано, что разрабатывается Background Synchronization, то есть в будущем можно будет в фоне через метод PeriodicSync’а обновлять данные для Service Worker’а. Но пока мы используем проверенные метки времени.
Когда мы тестировали офлайн-приложение в метро, возникла ситуация, когда приложение инициализировалось, но данные не поступили. Что могло произойти? С непонятным состоянием интернета в метро, Service Worker не понимал, есть ли интернет или нет, и образовывалась задержка.
Решилось очень просто. Мы посылаем запрос не через Fetch, а через PostMessage из нашего SPA приложения просим Service Worker’а: «А ну-ка, дружище, отдай нам данные, которые у тебя есть в кэше!»
У нас уже был один Service Worker с сервисом push-уведомлений, а теперь мы разработали второй. Просто задать им разный scope не подходит, потому что и push-уведомления, и офлайн-версия должны работать на всем сайте.
Задать корневой Scope тоже нельзя, потому что Service Worker, установленный позднее, заместит собой более раннюю версию. Сделать один файл Service Worker и в него заимпортить скрипты с разными сервисами тоже не получилось из-за похожей обработки событий.
Поэтому пришлось банально все переписать заново. Точнее, логика осталась, но мы сделали одно большое PWA-приложение для работы в Service Worker’е и уже в него подключили отдельные сервисы.
На данный момент это только Push-уведомления и офлайн–версия, но возможно в будущем нам пригодится такой модульный подход для чего-то еще.
Настал тот момент, когда мы вроде бы уже все сделали, все отлажено и мы запускаем Service Worker в нашу офлайн-версию на продакшн.
Но не все пошло гладко, на всех страницах сайта офлайн-версия работала. Но были страницы с видеоплеером, при включении которого видео отдавалось с огромной задержкой в минуты, т.к. оно тоже проходило через Service Worker.
Мы поняли, что через Service Worker не нужно пропускать что-либо, кроме самого документа страницы, и добавили соответствующий фильтр. Правда, все равно не сработало, потому что видео отдавалось тоже внутри Service Worker с таким заголовком. Пришлось дополнительно исключать видео из всех запросов.
Есть еще одна проблема – это аналитика. Интернета у нас нет, запросы не отправляются, а знать, что там происходит нам очень хочется.
Самый простой вариант, отправлять данные в GA, если в процессе чтения приложения появляется интернет. Но что делать с пользователями, которые закрыли приложение до появления сети. Давайте хранить аналитику на клиенте, и отправлять ее позже. Решили, что лучшим вариантом для хранения будет Index DB.
Это стандарт хранения больших объемов структурированной информации на клиенте, который
В нашем небольшом приложении нужны только первый и последний пункты.
Теперь схема выглядит так:
Прикрутив эту штуку, мы нашли примерно 10% пропавшей аудитории.
Когда мы только запускались, данные были, скажем, так себе – 2 тысячи пользователей в сутки. Для нашего сайта это небольшая цифра, сказалась, в том числе, необходимость установки Service Worker’а, то есть своего рода инфицирование пользователя.
На данный момент мы имеем около 6 тысяч пользователей в сутки. Это порядка 180 000 в месяц.
Еще мы замеряем, сколько пользователей пришло к нам из офлайна на основную версию сайта – это около 3 000. Несложно посчитать, что половина куда-то пропали – с этим мы разбираемся.
Когда мы только запускали приложение, мы рассчитывали на мобильную аудиторию – метро, дача, рыбалка и т.д. Но после запуска оказалось, что 30% это десктопы. Для нас это было, честно говоря, неожиданно! На десктопах у нас до сих пор это выглядит, как просто мобильная версия, но в планах исправить.
Некоторое время назад была новость о блокировке российских СМИ на Украине. Вообще тема блокировок и у нас достаточно актуальна. Пока админы настраивают бесконечные зеркала, мы с вами можем сообщить пользователю о переезде на другой домен или дать какую-то информацию.
Поможет в этом нам тот же Service Worker!
Когда провайдер блокирует сайт по урлу, он в большинстве случаев делает простой 302 редирект. В итоге нам всего-то и нужно отловить 302 статус ответа сервера через Fetch.
Как уже было сказано, когда мы уходим через Fetch в исключения, мы наоборот отлавливаем request и проверяем на response.status. Здесь response.status = 0 – не 302 или 301, а именно 0. Service Worker в случае редиректов не понимает вообще, что происходит у вас на сервере и отдает статус 0.
Для отлавливания ошибок сервера 5ХХ надо модифицировать предыдущий вариант. Все то же самое, но статус приходит правильный, поэтому мы можем спокойно ловить и показывать какой-то контент.
Это можно использовать, если у вас наглухо лежит сервак, пока админы пытаются его поднять, front героически отдает какую-то информацию либо из кэша, либо из резервного источника.
В IE, Edge и Safari Service Worker’ не работает:
На самом деле, он там есть, но выключен по умолчанию. Его можно включить через функции разработчика, но для продакшн и для пользователей вы его не запустите.
В мобильных браузерах, тоже не так уж все и плохо. Все работает в Android Browser 5-6 версии и в Chrome for Android – это примерно 55% нашей аудитории.
? Offline работает уже сейчас.
? Как бонус, можно отлавливать ошибки, редирект и вообще любые статусы.
? Расширение доступности сайта — теперь вы не только в online, но и в offline.
P.S.: Работа с offline – это часть PWA (Progressive Web Applications) но мы специально обошли эту тему стороной.
Гитхаб профили Алексея Чернышева – https://github.com/nanomen и
Максима Чагина – https://github.com/maxchagin.
В ответах на вопросы от слушателей нередко полно занимательной информации. Их мы спрятали под спойлер, практически в первозданном виде, т.е. с максимальным количеством подробностей.
Дорогие друзья, наверняка вы тоже сталкиваетесь с интересными задачами и находите элегантные пути решения. Не надо их недооценивать, вам кажется, что все просто, потому что вы уже все сделали, а кто-то еще не знает с чего начать.
Выберете подходящее направление на фестивале конференции РИТ++ и отправьте заявку программному комитету. Для тех, кто сомневается в своих лекторских способностях, напоминаем, что уж в этом мы вам поможем.
Оffline-версия уже доступна для любого сайта
Давайте представим – у нас сервис доставки пиццы. Клиент заходит, но у него нет интернета. Он ждет 20 секунд и видит все то же самое: «Нет подключения к интернету». Не думаю, что это остановит его от заказа, если у нас действительно вкусная пицца.
Но вы уверены, что для того, чтобы зайти на сайт, выбрать пиццу, наполнить ее ингредиентами, отправить форму заказа, нам действительно нужен интернет? Да нет, конечно! Все это можно сделать и офлайн, а когда появится соединение, отправить заказ уже на сервер для обработки.
Если интернет так и не появился, можно отправить нотификацию: «Ой! Свяжись с менеджером по телефону или останешься голодным!» Вариант, конечно не идеальный, но лучше, чем ничего.
Это может быть абсолютно любой кейс. Если у вас интернет-магазин, можно пользователю сообщить о распродаже. В случае информационного контента, можно дать почитать интересные материалы.
Service Worker – сердце offline-приложений
Вся работа в офлайн строится на использовании Service Worker. У него есть много свойств, но мы поговорим только об основных базовых частях, которые помогут понять, что вообще происходит с офлайном.
Итак, Service Worker – это событийно-управляемый воркер, который получает в себя JavaScript файл, выполняет его, и позволяет:
? Контролировать страницы, в контексте которых это Service Worker был вызван;
? Перехватывать различные запросы и модифицировать их на подконтрольных страницах;
? Кэшировать ресурсы через специальное кэш API.
Также хочется отметить, что он работает в потоке, параллельном от основного, и соответственно, ему не доступен DOM, LocalStorage или объект Window. Но зато он, выполняя какие-то действия, не блокирует основной UI браузера.
Принцип работы Service Worker
Чтобы Service Workerв принципе мог заработать на сайте, и вся магия смогла действовать, его нужно зарегистрировать, потом он должен пройти этап установки и этап активации.
Регистрация Service Worker
На клиенте нужно вызвать код, который передает путь до нашего Service Worker. Еслиэтот файл доступен и его можно выполнить без ошибок, тогда Service Worker считается зарегистрированным, и начинает прослушивать и просматривать те страницы, которые находятся в его области видимости.
Немножко про область видимости
- Если Service Worker положить в корень сайта, рядом с Favicon, то он будет видеть все страницы, которые находятся внутри сайта.
- Если его положить в какой-то подкаталог, то он будет действовать только в странице, которая находится внутри этого каталога.
- Можно программно ограничить его область видимости через свойство scope. В примере мы ограничили его, чтобы он работал только в подкаталоге article.
Установка Service Worker
Первое событие, которое возникает – это событие установки. Обрабатывая это событие, мы кэшируем ресурсы, которые впоследствии будем использовать для отдачи клиенту офлайн-версии, через кэш API в браузер.
Активация Service Worker
После этого срабатывает событие активации. Заметим, если Service Worker только в первый раз регистрируется и активируется на странице, то после этого сразу срабатывает событие активации и можно что-то сделать, обрабатывая это событие.
При обновлении Service Worker’а порядок активации отличается. Если до этого на сайте уже была какая-то его версия, а мы изменили файл, браузер, который примерно через сутки проверяет идентичность, понимает: «Ага, у меня новая версия Service Worker лежит на сайте, давайте-ка я ее обновлю!»
После этого в новом Service Worker’е запускается регистрация и установка. Но, если у пользователя открыты страницы со старым Service Worker’ом, новый Service Worker переходит в режим ожидания. Только после того, как они будут закрыты, срабатывает событие активации, и он может продолжать работать, в этот момент можно прибраться за старым Service Worker’ом и удалить ненужные данные.
Слушаем события
После того, как мы обработали активацию, Service Worker начинает работать в полную силу, а именно ему доступны следующие события:
- Message позволяет с клиентской стороны сказать Service Worker’у что-либо сделать, т.е. посылать сообщение через Post message.
- Fetch – одно из самых важных событий в офлайн-методике. Возникает, когда в подконтрольных Service Worker’у страницах запрашивается какой-либо ресурс. Обрабатывая событие Fetch, мы можем отправить нужный ответ на страницу.
- Push возникает, когда от какого-либо сервиса приходит Push-уведомление в браузер.
- Sync возникает, когда мы хотим на клиенте в фоне обновить какие-то данные для Service Worker’а.
Подходы к построению offline-приложений
Теперь, когда мы знаем, что такое Service Worker и что с его помощью можно управлять кэшом, выделим основные стратегии построения офлайн-приложения.
1. Статика.
Берем вообще все, что есть на странице – HTML. CSS, JS, Fonts, SVG, IMG и закидываем в кэш. Это самый простой и быстрый способ сделать ваше приложение доступным в офлайн, но у него есть существенный недостаток. Он подходит для редко обновляемого статического контента, если информация меняется чаще, чем пользователь заходит на сайт, то возможно она попросту утратит свою актуальность и станет никому не нужна.
Такой вариант можно применить для кэширования расписания конференции. У нас уже есть докладчики, все собрано и скомпилировано – закинули в кэш, и все счастливы.
2. Offline first, или неубиваемый сервис.
Это способ создания приложения, где подключение к интернету является своего рода усовершенствованием, а не необходимостью. По умолчанию мы считаем, что интернета у нас нет. Вся серверная логика переносится на клиент.
Как только появляется интернет, клиентская часть синхронизируется при необходимости с серверной, а пользователь продолжает работу, как ни в чем не бывало.
Например, у нас есть сервис публикации новостей, редактор может там писать и делать, что угодно, без интернета, а когда интернет появится, все синхронизируется с сервером, и можно будет выводить контент на сайт.
3. SPA
Это развертывание мини-приложения со своей структурой, адресацией, дизайном. Как мы уже говорили, в таком мини-приложении мы перехватываем запрос от пользователя, и в случае, если у него нет интернета, выставляем какой-то контент.
Это может быть все, что угодно – игра, интерактив, опрос. Такой вариант не подходит для сервисов в силу того, что у нас фактически происходит подмена контента, но для информационного, развлекательного ресурса это идеальный вариант.
У себя мы используем именно его расскажем о нем чуть подробнее.
Идея создания offline-версии rg.ru
Итак, на конференции Moscow JS коллеги из Лента.ру рассказали, что ни предлагают поиграть в крестики-нолики, если в процессе чтения приложения у пользователя пропадает интернет. Сама идея нам показалась интересной, но одной игрушки мало. Мы рассудили, что пользователь видит все то же сообщение и это банально.
Другой вариант: пользователь заходит на сайт и, пока у него нет интернета, ему предлагают почитать статьи. Это уже лучше – по крайней мере, есть шанс, что мы завладели вниманием пользователя, и после того, как у него появится интернет, он продолжит читать дальше на основном сайте.
Описание интерфейса
Первое, что приходит в голову, когда пытаешься представить себе офлайн-приложение, это 2 страничный SPA: главная страница со списком новостей, и можно открыть любую для прочтения.
Важный вопрос — как сообщить пользователю, что у него открылась офлайн-версия, чтобы он не подумал, что сайт теперь так выглядит. Мы пробовали много разных вариантов, но остановились на простой максимально заметной плашке сверху, которая сообщает, что это офлайн -версия и тут нет рекламы. В правом верхнем углу есть индикатор красного цвета, на котором написано «Offline», как только интернет появляется, он становится зеленым, сигнализируя о том, что доступна целевая страница.
Фильтруем контент
Надо заметить, что в офлайн попадают не все материалы подряд. Это связано со спецификой информационного контента. Представьте, приложение может быть открыто и через неделю, и через месяц после последнего посещения, а мы в июне-июле покажем пользователю что-то вроде «20 мая в Москве потеплеет до климатической нормы». С другой стороны, советы, как сохранить здоровье после 25, всегда актуальны.
Как работает offline-версия сайта rg.ru
Для того, чтобы это все сработало, необходимо хотя бы раз зайти на сайт. После входа на сайт инициализируется Service Worker, добавив в кэш всю необходимую информацию.
Архитектура offline-приложения
Пользователь заходит на сайт и на клиентской стороне страницы включается регистрация Service Worker’а, мы отдаем пользователю в кэш несколько файлов для офлайн-версии, а после этого удаляем ненужное старое.
Далее начинаем проверять доступность самой страницы через события Fetch. А именно, обрабатывая событие Fetch, мы смотрим, если запрашиваемый ресурс доступен, то мы его просто отдаем. Если же нет, уходим в исключение и отдаем через кэш API нашу офлайн-версию.
Пока Service Worker все проверяет и обрабатывает, мы параллельно выясняем, нужно ли обновить данные для офлайн-версии пользователю.
Принцип работы приложения
Как уже было сказано, офлайн-версия – это SPA приложение, построенное по стандартной MVC архитектуре: есть контроллер, который получает в нашем случае всего 2 адреса, главной страницы или страницы статьи. Мы забираем данные из кэша и нужный нам кусочек шаблона и отдаем пользователю уже готовую HTML.
Кстати, здесь мы не используем никакие библиотеки типа React или Angular. У нас только шаблонизатор Mustache и обычный JavaScript – просто, чтобы все это не перетаскивать пользователю в браузер.
Доступность сети
Теперь нужно решить, как узнать, что интернет появился. События ONONLINE и ONOFFLINE, к сожалению, не подходят, потому что возникают, когда из сетевой карты выдергивается сетевой шнур. И мы пошли в лоб, и это оказалось эффективно.
Через определенный интервал времени внутри приложения отправляется статистика в Google Analytics – если статистика отправилась, мы понимаем, что интернет появился и сообщаем об этом пользователю.
Проблемы…
Когда мы разрабатывали эту версию и запускали ее на продакшн, мы столкнулись с рядом проблем, которыми хотим с вами поделиться, чтобы вы не наступили те же грабли.
Обновление данных
— Кэп, у нас проблема! Нужно обновлять закэшированные данные, чтобы пользователь всегда видел актуальную версию новостей.
— Может, у тебя есть какие-то идеи? Ты же это разрабатываешь!
Первое, что приходит в голову, конечно же, setinterval внутри Service Worker’а – почему бы и нет? Мы провели небольшой эксперимент. Внутри Service Worker’а написали функцию, которая в цикле каждые 10 секунд отправляла простой get запрос на сервер, все данные логировались. После этого заходим на тестовую страницу, чтобы Service Worker инициализировался, закрываем вкладку и ждем, пока Service Worker умрет.
Выяснилось следующее:
- В Google Chrome на десктопе Service Worker умирает, то есть перестает отправлять запросы, ровно через 1 минуту.
- FireFox отправляет запросы бесконечно, пока браузер открыт Service Worker продолжает работать.
- В мобильном Chrome’е Service Worker также работает бесконечно, даже если убрать браузер из приложений, он все равно отправляет запросы.
В принципе, с setinterval можно работать. Но мы не стали его использовать:
- Потому, что неизвестно, сколько это жрет батареи.
- Неизвестно, что будет в следующей версии, вдруг Google ограничит отправку запросов одной минутой, как на десктопе.
Поэтому мы, как и с проверкой на доступность сети, решили пойти обходным путем. Если пользователь заходит на страницу, когда есть интернет:
- Ему записывается метка времени в Local Storage.
- При перезагрузке страницы или ее повторном посещении опять снимается метка времени и сравнивается с той, которая была записана в Local Storage.
Таким образом вычисляется, сколько времени прошло с последнего посещения нашего сайта, и если больше 15 минут, в Service Worker отправляется запрос: «Дружище, пора бы удалить из кэша старые данные и записать туда новые!»
В документации написано, что разрабатывается Background Synchronization, то есть в будущем можно будет в фоне через метод PeriodicSync’а обновлять данные для Service Worker’а. Но пока мы используем проверенные метки времени.
Задержки при получении данных
Когда мы тестировали офлайн-приложение в метро, возникла ситуация, когда приложение инициализировалось, но данные не поступили. Что могло произойти? С непонятным состоянием интернета в метро, Service Worker не понимал, есть ли интернет или нет, и образовывалась задержка.
Решилось очень просто. Мы посылаем запрос не через Fetch, а через PostMessage из нашего SPA приложения просим Service Worker’а: «А ну-ка, дружище, отдай нам данные, которые у тебя есть в кэше!»
Два Service Worker в одном scope
У нас уже был один Service Worker с сервисом push-уведомлений, а теперь мы разработали второй. Просто задать им разный scope не подходит, потому что и push-уведомления, и офлайн-версия должны работать на всем сайте.
Задать корневой Scope тоже нельзя, потому что Service Worker, установленный позднее, заместит собой более раннюю версию. Сделать один файл Service Worker и в него заимпортить скрипты с разными сервисами тоже не получилось из-за похожей обработки событий.
Поэтому пришлось банально все переписать заново. Точнее, логика осталась, но мы сделали одно большое PWA-приложение для работы в Service Worker’е и уже в него подключили отдельные сервисы.
На данный момент это только Push-уведомления и офлайн–версия, но возможно в будущем нам пригодится такой модульный подход для чего-то еще.
Банальный совет – лучше заранее сделать полностью модульную структуру в Service Worker’е, чтобы потом не пришлось переписывать.
Проксирование трафика через Service Worker
Настал тот момент, когда мы вроде бы уже все сделали, все отлажено и мы запускаем Service Worker в нашу офлайн-версию на продакшн.
Но не все пошло гладко, на всех страницах сайта офлайн-версия работала. Но были страницы с видеоплеером, при включении которого видео отдавалось с огромной задержкой в минуты, т.к. оно тоже проходило через Service Worker.
Мы поняли, что через Service Worker не нужно пропускать что-либо, кроме самого документа страницы, и добавили соответствующий фильтр. Правда, все равно не сработало, потому что видео отдавалось тоже внутри Service Worker с таким заголовком. Пришлось дополнительно исключать видео из всех запросов.
Аналитика
Есть еще одна проблема – это аналитика. Интернета у нас нет, запросы не отправляются, а знать, что там происходит нам очень хочется.
Самый простой вариант, отправлять данные в GA, если в процессе чтения приложения появляется интернет. Но что делать с пользователями, которые закрыли приложение до появления сети. Давайте хранить аналитику на клиенте, и отправлять ее позже. Решили, что лучшим вариантом для хранения будет Index DB.
Это стандарт хранения больших объемов структурированной информации на клиенте, который
- работает асинхронно;
- поддерживает транзакции;
- умеет работать с индексами;
- работает непосредственно прямо из Service Worker’а.
В нашем небольшом приложении нужны только первый и последний пункты.
Теперь схема выглядит так:
- Пользователь ходит по странице;
- Все данные pageview отправляются в базу данных;
- Если данные отправляются, считаем, что интернет есть, база данных очищается;
- Если интернета нет, запрос не отправляется, ждем следующего цикла.
Прикрутив эту штуку, мы нашли примерно 10% пропавшей аудитории.
Что мы имеем на данный момент?
Когда мы только запускались, данные были, скажем, так себе – 2 тысячи пользователей в сутки. Для нашего сайта это небольшая цифра, сказалась, в том числе, необходимость установки Service Worker’а, то есть своего рода инфицирование пользователя.
На данный момент мы имеем около 6 тысяч пользователей в сутки. Это порядка 180 000 в месяц.
Еще мы замеряем, сколько пользователей пришло к нам из офлайна на основную версию сайта – это около 3 000. Несложно посчитать, что половина куда-то пропали – с этим мы разбираемся.
Когда мы только запускали приложение, мы рассчитывали на мобильную аудиторию – метро, дача, рыбалка и т.д. Но после запуска оказалось, что 30% это десктопы. Для нас это было, честно говоря, неожиданно! На десктопах у нас до сих пор это выглядит, как просто мобильная версия, но в планах исправить.
Неожиданные применения Service Worker’а. Блокировка сайтов
Некоторое время назад была новость о блокировке российских СМИ на Украине. Вообще тема блокировок и у нас достаточно актуальна. Пока админы настраивают бесконечные зеркала, мы с вами можем сообщить пользователю о переезде на другой домен или дать какую-то информацию.
Поможет в этом нам тот же Service Worker!
Когда провайдер блокирует сайт по урлу, он в большинстве случаев делает простой 302 редирект. В итоге нам всего-то и нужно отловить 302 статус ответа сервера через Fetch.
Как уже было сказано, когда мы уходим через Fetch в исключения, мы наоборот отлавливаем request и проверяем на response.status. Здесь response.status = 0 – не 302 или 301, а именно 0. Service Worker в случае редиректов не понимает вообще, что происходит у вас на сервере и отдает статус 0.
Для отлавливания ошибок сервера 5ХХ надо модифицировать предыдущий вариант. Все то же самое, но статус приходит правильный, поэтому мы можем спокойно ловить и показывать какой-то контент.
Это можно использовать, если у вас наглухо лежит сервак, пока админы пытаются его поднять, front героически отдает какую-то информацию либо из кэша, либо из резервного источника.
Немного о поддержке в браузерах
В IE, Edge и Safari Service Worker’ не работает:
- IЕ можно сразу забыть.
- Edge находится в стадии разработки без указания конкретных сроков.
- В Safari написано, что рассматривается поддержка в течение ближайших 5 лет.
На самом деле, он там есть, но выключен по умолчанию. Его можно включить через функции разработчика, но для продакшн и для пользователей вы его не запустите.
В мобильных браузерах, тоже не так уж все и плохо. Все работает в Android Browser 5-6 версии и в Chrome for Android – это примерно 55% нашей аудитории.
Резюме
? Offline работает уже сейчас.
? Как бонус, можно отлавливать ошибки, редирект и вообще любые статусы.
? Расширение доступности сайта — теперь вы не только в online, но и в offline.
P.S.: Работа с offline – это часть PWA (Progressive Web Applications) но мы специально обошли эту тему стороной.
Гитхаб профили Алексея Чернышева – https://github.com/nanomen и
Максима Чагина – https://github.com/maxchagin.
В ответах на вопросы от слушателей нередко полно занимательной информации. Их мы спрятали под спойлер, практически в первозданном виде, т.е. с максимальным количеством подробностей.
Вопросы-ответы
— У меня 2 вопроса:
1. Первый – я бы хотел еще раз понять, как происходит инвалидация скриптов, которые загрузил Service Worker?
2. Второй вопрос – правильно ли я понимаю, что, когда я открываю какую-то новостную страничку, в которой есть популярные статьи, то по идее их можно заранее загрузить, чтобы в следующий раз, когда я на нее нажму на сайте, запрос на сервер не шел, а скачивалась бы сохраненная страничка?
Максим: Я сначала отвечу на второй вопрос. Теоретически, да, это возможно. Но дело в том, что ресурс обновляется очень быстро. Тебе же не интересно то, что было вчера? Есть вариант с Push-нотификацией. Пользователи, которые подписаны на Push–нотификацию, когда она приходит, Service Worker просыпается, и после этого может загрузить в кэш статью, которую мы «пушнули». В этом случае он может открыть ее даже без интернета.
В других случаях мы просто обновляем какие-то интересные статьи. У нас редакция помечает интересные статьи специальным тэгом и она отправляется заранее пользователю в кэш.
Алексей: Первый вопрос. Есть регистрация, установка и активация. Эти 3 события возникают только в тот момент, когда либо Service Worker устанавливается на сайте первый раз, либо когда мы в Service Worker файл поменяли руками и перезалили его. Каждые сутки смотрится эта хэш-сумма, проверяется браузером, обновился он или нет.
Только в этот момент опять срабатывает событие регистрация. Как раз во время регистрации он проверяет, надо его дальше обновлять или нет. И потом всплывает установка и активация.
Самый сложный момент – это активация. Представьте – есть 2 версии Service Worker’а: старая и новая. Старая работает. У пользователя открыты вкладки со старой версией. Он открывает новую страницу, и у него уже новый Service Worker пытается проломиться.
По соображениям разработчиков, если мы сейчас всем обновим Service Worker, тогда все эти старые страницы переломаются. Мало ли, что у нас Service Worker делает? Поэтому новый Service Worker устанавливается, он может что-то сделать в момент установки – в кэш что-то записать. И после этого он блокируется и начинает ждать. У него бесконечное ожидание, пока не закроются страницы, использующие старый Service Worker.
После того, как закроем их все или полностью браузер, новый Service Worker просит активацию. В этот момент мы что-то можем сделать (а можем и не сделать) – тут есть определенный инструментарий в Service Worker’е, и мы можем им пользоваться (или не пользоваться). Мы можем события установи и активации не обрабатывать. Мы там подчищаем то, что не нужно – старый кэш. Потом активация возникает – и все.
— Судя по вашим слайдам, у вас на всех Safari ничего нет?
Да, все это работает только на Android. В Safari это не работает в принципе. Если вы в мобильнике откроете, он не заработает. У нас была проблема – у руководства только Айфоны, они заходят и говорят: «Ребята, вы чем вообще занимаетесь?!»
— Отсюда и вопрос. По вашей же статистике это примерно 50% аудитории. А не пробовали AppCash использовать, как fallback?
Максим: Нет, не пробовали. На самом деле, эту штуку мы сделали, чтобы не то, чтобы поиграться, а интересно было. Поэтому что-то докручивать, допиливать нет смысла.
Алексей: Тут в чем дело? Все началось, как я и рассказывал, с нотификации. То есть вроде бы у нас уже есть Service Worker, а потом мы посмотрели доклад Лента.ру – они крестики-нолики сделали – почему бы и нет? Только давайте уже не игру, а ленту с новостями. И оно как-то поехало.
То есть у нас не было задачи – а давайте мы теперь еще и офлайн зацепим. Оно как-то случайно возникло. Просто в чем самый интерес – в том, что на самом деле написать эту офлайн версию не очень сложно. Самое сложное понять, как эти события отрабатываются. А так просто отдавать что-то из кэша совсем не сложно.
Мы по-быстрому ее запилили, а потом из этого стали возникать проблемы, про которые я рассказывал, в том числе с аналитикой.
Максим: У нас есть еще конкретная проблема – это монетизация. То есть пока мы не монетизируем офлайн, что-то делать на остальной процент аудитории достаточно бесполезно. Рекламы там нет.
— А как же лояльность пользователей?
Те, кто не знает, что сайт офлайн работает, они и не знают. Это не то, что необходимость, это именно бонус, довесок.
Алексей: Я бы даже добавил, что это скорее для тех, кто в принципе посещает сайт, а не просто зашел туда с поисковика случайно. Это бонус для постоянных посетителей. Я заметил, как жена залипла и всю дорогу в метро залипала новости. К сожалению, об этом нужно как-то узнать. Мы никакие баннеры по этому поводу не вешали, никому не говорили, что у нас офлайн.
— Что можно сделать, чтобы при первичной загрузке приложение быстрее работало? Я сейчас пробую – оно секунд 30 может висеть. В принципе, прикольно – там 10 статей есть, залипать в метро хватит.
Максим: Если у тебя нет интернета, то браузер пытается доконнектиться до него. В это время мы не можем ничего показать.
Алексей: В том-то и прикол Service Worker’а – внутри него, когда мы Fetch обрабатываем, этот запрос уходит в Promise, и он ждет – либо ему уйти в resolve, либо в reject. В этот момент гипотетически, может быть, можно что-то вне этого засунуть, но вряд ли. Мы либо то обрабатываем, либо то.
В том и была проблема – это наша больная тема, когда по глупости в SPA приложении самого офлайн мы запрашивали данные через Fetch. Раз нет интернета, зачем ты через Fetch запрашиваешь данные? Соответственно система пытается получить эти данные, а интернета нет, и так происходят задержки.
Та же история, если я нажимаю «Назад» — это чуть-чуть больше напрягает. Ходил по онлайн версии, потом пропал интернет, я попал в офлайн, нажал «Назад» — и он долго думает, пытаясь отправить запрос, а это не получается.
Если в настройках выключены мобильные и WI-FI, он в принципе тогда очень быстро тогда должен отлавливать. Был бы метод понять, что интернет не слишком хорош, чтобы отдать тебе полную версию – над этим надо работать.
— Мы тоже недавно сделали офлайн-версию, но мы не делали отдельную. Есть очень короткий вопрос – у вас правда 50% iOS?
45% iOS.
И по поводу самой технологии – вы, если я правильно понял, сначала по сети пытаетесь получить данные, потом подаете из кэша. Можно сделать наоборот и периодически их актуализировать.
И второй вопрос – что вы делаете с медиа ресурсами? Статья – это же не только текст, это еще какой-то обвес интерактивный, и что у вас с трафиком, как следствие?
Максим: Мы специально рассчитываем на мобильную аудиторию, поэтому мы не грузим вообще никаких медиа ресурсов туда. То есть там нет фотографий. Поэтому у нас следующая итерация – загрузка туда медиа. Мы собираемся оптимизировать это для десктоп, показывать изображения, превью и грузить медиа-контент. Думаю, до фоторепортажей и видео мы, скорее всего, не дойдем, но какое-то небольшое медиа там будет.
Алексей: Так вышло, мы любим пользователей. Просто не хочется все пихать в браузер. Гипотетически можно реально прямо полную статью закатать в кэш, проблем нет. Но зачем?
Максим: У нас есть рекламная служба, которая пихает баннеры по 2-3 мБ пользователю. Если мы еще будем этим заниматься, то совсем нехорошо получится.
Алексей: Добавлю насчет кэша. Здесь есть все-таки различие: есть кэш, в который браузер кэширует какую-то страницу, это понятно. Он сам ее кэширует и мы этим управлять не можем. А вот как раз кэш API – если мы закэшировали, пока сами не удалим, оно там и будет валяться. Поэтому не хочется.
— Два вопроса. Во-первых, вы сказали, что у вас внезапно оказалась треть офлайн на десктопах, и вы собираетесь с этим что-то делать. Но вы разобрались, кто эти люди?
Максим: Да, это люди в основном из регионов. Можно даже посмотреть – у нас есть монитор, и там выведена офлайн версия в реальном времени, где мы смотрим регионы. Падает посещаемость – хоп! – какой-то регион отрубился. Десктопы в основном оттуда. Это жизнь. Мы здесь, в Москве, не знаем об этом. Оказывается у людей на десктопах нет интернета.
— Второй вопрос – вы сказали, что можно отловить редирект и в этот момент в случае блокировки что-то свое туда пропихнуть. Тут не очень понятно. Если вас уже заблокировали, то как вы сможете сказать, куда переезжать?
Максим: Это надо заранее сделать в Service Worker’е. Мы же все заранее знаем, кого из нас заблокируют. Что тут скрывать? Мы – федеральное издание, и нас блокируют тоже – где-то кто-то указал не ту информацию – например, в Краснодаре нас заблокировали. Но мы сейчас не об этом.
Мы конкретно напряглись, когда на Украине СМИ начали блокировать, а нас, что обидно, не заблокировали! Вроде бы мы тоже крупное СМИ!
Это все надо заранее продумать и закинуть туда. При этом важный момент, что после того, как тебя заблокировали, ты уже Service Worker не обновишь – это уже мертвая точка. Там можно import script сделать, то есть такие хитрости — подгрузить его с другого домена, из CDN. В этом же домене Service Worker не обновится потому, что домен уже не существует, у тебя его уже отобрали.
Это может быть такая же страница сайта, ты можешь там написать: «Чувак, мы переехали сюда!» Как узнать заранее, куда переехали – это надо продумать! Тут должна быть стратегия продумывания на 5 лет вперед, как Safari делает.
Если у вас небольшой сайт и вас не будут блокировать, здесь клевая штука – это отлавливать ошибки сервера. Вообще потрясающая вещь, можно вообще без проблем показывать реальный контент, из кэша или резервного источника, Причем это делается буквально за 5 минут – просто копипастом.
Алексей: В Service Worker обычный JavaScript. Там ничего такого нет. Можно Fetch’и использовать без всяких полифилов. Если Service Worker работает, то уж Fetch точно будет работать. Плюс Е6 можно использовать вообще по полной. Хотите стрелочные функции – наслаждайтесь! Все без проблем, никаких полифилов, просто все грузите в Service Worker, и все будет работать.
1. Первый – я бы хотел еще раз понять, как происходит инвалидация скриптов, которые загрузил Service Worker?
2. Второй вопрос – правильно ли я понимаю, что, когда я открываю какую-то новостную страничку, в которой есть популярные статьи, то по идее их можно заранее загрузить, чтобы в следующий раз, когда я на нее нажму на сайте, запрос на сервер не шел, а скачивалась бы сохраненная страничка?
Максим: Я сначала отвечу на второй вопрос. Теоретически, да, это возможно. Но дело в том, что ресурс обновляется очень быстро. Тебе же не интересно то, что было вчера? Есть вариант с Push-нотификацией. Пользователи, которые подписаны на Push–нотификацию, когда она приходит, Service Worker просыпается, и после этого может загрузить в кэш статью, которую мы «пушнули». В этом случае он может открыть ее даже без интернета.
В других случаях мы просто обновляем какие-то интересные статьи. У нас редакция помечает интересные статьи специальным тэгом и она отправляется заранее пользователю в кэш.
Алексей: Первый вопрос. Есть регистрация, установка и активация. Эти 3 события возникают только в тот момент, когда либо Service Worker устанавливается на сайте первый раз, либо когда мы в Service Worker файл поменяли руками и перезалили его. Каждые сутки смотрится эта хэш-сумма, проверяется браузером, обновился он или нет.
Только в этот момент опять срабатывает событие регистрация. Как раз во время регистрации он проверяет, надо его дальше обновлять или нет. И потом всплывает установка и активация.
Самый сложный момент – это активация. Представьте – есть 2 версии Service Worker’а: старая и новая. Старая работает. У пользователя открыты вкладки со старой версией. Он открывает новую страницу, и у него уже новый Service Worker пытается проломиться.
По соображениям разработчиков, если мы сейчас всем обновим Service Worker, тогда все эти старые страницы переломаются. Мало ли, что у нас Service Worker делает? Поэтому новый Service Worker устанавливается, он может что-то сделать в момент установки – в кэш что-то записать. И после этого он блокируется и начинает ждать. У него бесконечное ожидание, пока не закроются страницы, использующие старый Service Worker.
После того, как закроем их все или полностью браузер, новый Service Worker просит активацию. В этот момент мы что-то можем сделать (а можем и не сделать) – тут есть определенный инструментарий в Service Worker’е, и мы можем им пользоваться (или не пользоваться). Мы можем события установи и активации не обрабатывать. Мы там подчищаем то, что не нужно – старый кэш. Потом активация возникает – и все.
— Судя по вашим слайдам, у вас на всех Safari ничего нет?
Да, все это работает только на Android. В Safari это не работает в принципе. Если вы в мобильнике откроете, он не заработает. У нас была проблема – у руководства только Айфоны, они заходят и говорят: «Ребята, вы чем вообще занимаетесь?!»
— Отсюда и вопрос. По вашей же статистике это примерно 50% аудитории. А не пробовали AppCash использовать, как fallback?
Максим: Нет, не пробовали. На самом деле, эту штуку мы сделали, чтобы не то, чтобы поиграться, а интересно было. Поэтому что-то докручивать, допиливать нет смысла.
Алексей: Тут в чем дело? Все началось, как я и рассказывал, с нотификации. То есть вроде бы у нас уже есть Service Worker, а потом мы посмотрели доклад Лента.ру – они крестики-нолики сделали – почему бы и нет? Только давайте уже не игру, а ленту с новостями. И оно как-то поехало.
То есть у нас не было задачи – а давайте мы теперь еще и офлайн зацепим. Оно как-то случайно возникло. Просто в чем самый интерес – в том, что на самом деле написать эту офлайн версию не очень сложно. Самое сложное понять, как эти события отрабатываются. А так просто отдавать что-то из кэша совсем не сложно.
Мы по-быстрому ее запилили, а потом из этого стали возникать проблемы, про которые я рассказывал, в том числе с аналитикой.
Максим: У нас есть еще конкретная проблема – это монетизация. То есть пока мы не монетизируем офлайн, что-то делать на остальной процент аудитории достаточно бесполезно. Рекламы там нет.
— А как же лояльность пользователей?
Те, кто не знает, что сайт офлайн работает, они и не знают. Это не то, что необходимость, это именно бонус, довесок.
Алексей: Я бы даже добавил, что это скорее для тех, кто в принципе посещает сайт, а не просто зашел туда с поисковика случайно. Это бонус для постоянных посетителей. Я заметил, как жена залипла и всю дорогу в метро залипала новости. К сожалению, об этом нужно как-то узнать. Мы никакие баннеры по этому поводу не вешали, никому не говорили, что у нас офлайн.
— Что можно сделать, чтобы при первичной загрузке приложение быстрее работало? Я сейчас пробую – оно секунд 30 может висеть. В принципе, прикольно – там 10 статей есть, залипать в метро хватит.
Максим: Если у тебя нет интернета, то браузер пытается доконнектиться до него. В это время мы не можем ничего показать.
Алексей: В том-то и прикол Service Worker’а – внутри него, когда мы Fetch обрабатываем, этот запрос уходит в Promise, и он ждет – либо ему уйти в resolve, либо в reject. В этот момент гипотетически, может быть, можно что-то вне этого засунуть, но вряд ли. Мы либо то обрабатываем, либо то.
В том и была проблема – это наша больная тема, когда по глупости в SPA приложении самого офлайн мы запрашивали данные через Fetch. Раз нет интернета, зачем ты через Fetch запрашиваешь данные? Соответственно система пытается получить эти данные, а интернета нет, и так происходят задержки.
Та же история, если я нажимаю «Назад» — это чуть-чуть больше напрягает. Ходил по онлайн версии, потом пропал интернет, я попал в офлайн, нажал «Назад» — и он долго думает, пытаясь отправить запрос, а это не получается.
Если в настройках выключены мобильные и WI-FI, он в принципе тогда очень быстро тогда должен отлавливать. Был бы метод понять, что интернет не слишком хорош, чтобы отдать тебе полную версию – над этим надо работать.
— Мы тоже недавно сделали офлайн-версию, но мы не делали отдельную. Есть очень короткий вопрос – у вас правда 50% iOS?
45% iOS.
И по поводу самой технологии – вы, если я правильно понял, сначала по сети пытаетесь получить данные, потом подаете из кэша. Можно сделать наоборот и периодически их актуализировать.
И второй вопрос – что вы делаете с медиа ресурсами? Статья – это же не только текст, это еще какой-то обвес интерактивный, и что у вас с трафиком, как следствие?
Максим: Мы специально рассчитываем на мобильную аудиторию, поэтому мы не грузим вообще никаких медиа ресурсов туда. То есть там нет фотографий. Поэтому у нас следующая итерация – загрузка туда медиа. Мы собираемся оптимизировать это для десктоп, показывать изображения, превью и грузить медиа-контент. Думаю, до фоторепортажей и видео мы, скорее всего, не дойдем, но какое-то небольшое медиа там будет.
Алексей: Так вышло, мы любим пользователей. Просто не хочется все пихать в браузер. Гипотетически можно реально прямо полную статью закатать в кэш, проблем нет. Но зачем?
Максим: У нас есть рекламная служба, которая пихает баннеры по 2-3 мБ пользователю. Если мы еще будем этим заниматься, то совсем нехорошо получится.
Алексей: Добавлю насчет кэша. Здесь есть все-таки различие: есть кэш, в который браузер кэширует какую-то страницу, это понятно. Он сам ее кэширует и мы этим управлять не можем. А вот как раз кэш API – если мы закэшировали, пока сами не удалим, оно там и будет валяться. Поэтому не хочется.
— Два вопроса. Во-первых, вы сказали, что у вас внезапно оказалась треть офлайн на десктопах, и вы собираетесь с этим что-то делать. Но вы разобрались, кто эти люди?
Максим: Да, это люди в основном из регионов. Можно даже посмотреть – у нас есть монитор, и там выведена офлайн версия в реальном времени, где мы смотрим регионы. Падает посещаемость – хоп! – какой-то регион отрубился. Десктопы в основном оттуда. Это жизнь. Мы здесь, в Москве, не знаем об этом. Оказывается у людей на десктопах нет интернета.
— Второй вопрос – вы сказали, что можно отловить редирект и в этот момент в случае блокировки что-то свое туда пропихнуть. Тут не очень понятно. Если вас уже заблокировали, то как вы сможете сказать, куда переезжать?
Максим: Это надо заранее сделать в Service Worker’е. Мы же все заранее знаем, кого из нас заблокируют. Что тут скрывать? Мы – федеральное издание, и нас блокируют тоже – где-то кто-то указал не ту информацию – например, в Краснодаре нас заблокировали. Но мы сейчас не об этом.
Мы конкретно напряглись, когда на Украине СМИ начали блокировать, а нас, что обидно, не заблокировали! Вроде бы мы тоже крупное СМИ!
Это все надо заранее продумать и закинуть туда. При этом важный момент, что после того, как тебя заблокировали, ты уже Service Worker не обновишь – это уже мертвая точка. Там можно import script сделать, то есть такие хитрости — подгрузить его с другого домена, из CDN. В этом же домене Service Worker не обновится потому, что домен уже не существует, у тебя его уже отобрали.
Это может быть такая же страница сайта, ты можешь там написать: «Чувак, мы переехали сюда!» Как узнать заранее, куда переехали – это надо продумать! Тут должна быть стратегия продумывания на 5 лет вперед, как Safari делает.
Если у вас небольшой сайт и вас не будут блокировать, здесь клевая штука – это отлавливать ошибки сервера. Вообще потрясающая вещь, можно вообще без проблем показывать реальный контент, из кэша или резервного источника, Причем это делается буквально за 5 минут – просто копипастом.
Алексей: В Service Worker обычный JavaScript. Там ничего такого нет. Можно Fetch’и использовать без всяких полифилов. Если Service Worker работает, то уж Fetch точно будет работать. Плюс Е6 можно использовать вообще по полной. Хотите стрелочные функции – наслаждайтесь! Все без проблем, никаких полифилов, просто все грузите в Service Worker, и все будет работать.
Приходите делиться опытом
Дорогие друзья, наверняка вы тоже сталкиваетесь с интересными задачами и находите элегантные пути решения. Не надо их недооценивать, вам кажется, что все просто, потому что вы уже все сделали, а кто-то еще не знает с чего начать.
Выберете подходящее направление на фестивале конференции РИТ++ и отправьте заявку программному комитету. Для тех, кто сомневается в своих лекторских способностях, напоминаем, что уж в этом мы вам поможем.
Комментарии (8)
AkshinM
04.02.2018 00:35хорошая статья. если не трудно выложите текстуру заднего фона фотографий. очень понравилась
john_samilin
05.02.2018 11:44Я бы сказал, что для этой цели (кэширование статей) идеально подходит CouchDB с их системой синхронизации и сохранением в IndexedDB. Не надо было бы напрягаться с обновлением сервис-воркера до новой версии (а это больно, я проверял).
Вообще я считаю, что offline first подход должен быть везде, где нет необходимости в real time. В первую очередь в таких приложениях, как Booking, Couchsurfing и Google Now
shifttstas
«доступ к Интернет», серьёзно?
Лучше выбрать что-то из:
Зачем писать Вас и Интернет с большой буквы да еще и не склонять? это «особенность» аудитории сайта?
frog
А по-моему, всё верно написано. Правда, лучше бы звучало «доступ к сети Интернет».
en.wikipedia.org/wiki/Capitalization_of_%22Internet%22
shifttstas
я о склонении, а не о капитализации…
frog
Что касается склонения, то вполне допустимы оба варианта. Но (на мой взгляд) «к сети Интернет» — это официальное формальное, а «к Интернету» — разговорное неформальное
shifttstas
и? все равно вы предлагаете или добавить слово «сети» или склонить интернет, а чем вариант смены предлога не понравился? на мой взгляд он самый оптимальный.