service workers что это
Service Workers
В этой статье я хотел бы поговорить о Service Workers (SW). SW позволяют нам сделать наше приложение готовым к работе в автономном режиме, чтобы оно работало, даже если у нас нет подключения к Интернету. Они также позволяют нам использовать множество других расширенных функций, таких как push-уведомления или фоновая синхронизация. SW продолжает работать даже после закрытия браузера, то есть Service Workers продолжают работать. Это фоновый процесс. Итак, давайте зарегистрируем нашего первого Service Worker’a.
(В этой статье я реализую функциональность, связанную с SW, на простом JS, поскольку код написан на простом JS, мы можем интегрировать в любые JS-фреймворки, такие как Angular, React или Vue)
В качестве первого шага добавим файл sw.js в корневую папку проекта. В app.js мы должны проверить, доступен ли SW в навигаторе, то есть поддерживаются ли SW данным браузером. Теперь, когда мы знаем, что SW доступны, мы можем выполнить метод navigator.serviceWorker.register (), указывая путь к файлу, в котором находится наш SW, чтобы его зарегистрировать. Этот метод фактически возвращает Promise. Итак, чтобы получить информацию, как только это будет сделано, мы можем присоединиться к нему.
Поскольку мы зарегистрировали нашего первого SW, давайте добавим наш первый прослушиватель событий. Как я уже сказал, SW работают в фоновом режиме. Но я не упомянул одну вещь, что все они связаны с обработкой событий. Чтобы прикрепить слушателей событий к SW, мы, прежде всего, должны обратиться к нему с помощью ключевого слова self, что в основном означает «предоставь мне доступ к SW», а затем мы можем выполнить метод addEventListener (). SW надают доступ к специальному набору событий, например, к событию установки, которое запускается, когда браузер устанавливает Service Worker’a. Здесь мы выполняем функцию и получаем объект события, который автоматически передается в функцию браузером, и этот объект предоставляет нам информацию о событии установки. Как мы видим, наш Service Worker успешно установлен.
Теперь посмотрим, действительно ли эти файлы загружены в кеш-память.
Выражение event.respondWith () позволяет нам перезаписывать данные, которые отправляются обратно. Вы можете думать о Service Worker’е как о сетевом прокси, по крайней мере, если мы используем здесь событие fetch. Таким образом, каждый исходящий запрос на выборку проходит через Service Worker, как и каждый ответ. То есть, если мы ничего не делаем, ответ просто не передается. Выражение cashes.match () позволяет нам проверить, кэширован ли уже данный запрос. Если это так, он вернет кешированный ответ. Мы не делаем сетевой запрос, мы перехватываем запрос и не выдаем новый, вместо этого мы просто смотрим на то, что мы хотели запросить, и видим, есть ли оно в кеше и если есть, мы возвращаем его обратно. С другой стороны, если мы не находим его в кеше, мы хотим вернуть запрос на выборку там, где мы обращаемся или где мы просто продолжаем исходный запрос, поэтому вертаем fetch (event.request). После всех этих изменений мы наконец можем использовать наше веб-приложение в автономном режиме.
Как видите, наше веб-приложение содержит диаграмму с некоторыми статическими данными, и при нажатии кнопки «ПОЛУЧИТЬ ДАННЫЕ» ничего не происходит. Теперь я хочу сделать так, чтобы нажав эту кнопку, мы получили некоторые статистические данные, отобразили их на диаграмме и сохранили эти данные в кеше. Таким образом, мы реализуем динамическое кеширование. Итак, приступим. Допустим, у нас есть эндпоинт, который возвращает статистические данные о том, сколько пользователей посетили наш сайт. Итак, теперь мы должны взять эти данные и отобразить их на графике.
Как и раньше, я добавлю решение, а затем объясню, как оно работает.
Сначала нам нужно проверить тег события. Затем я использую event.waitUntil (), как и раньше, это просто позволяет мне убедиться, что событие не завершилось преждевременно. Затем мы получаем данные, которые хранятся в indexedDB (используя вспомогательную функцию из utility.js), перебираем их, отправляем post запрос для каждого из сохраняемых фрагментов данных, а затем удаляем их из indexedDB, если мы успешно отправили их на сервер. Вот и все. Давайте теперь попробуем это. Чтобы проверить эту функциональность, мы должны перейти в автономный режим в нашем браузере, нажать кнопку «POST DATA» и затем снова выйти в онлайн.
После нажатия кнопки «POST DATA», когда мы не в сети, ничего не происходит, но когда подключение восстанавливается, мы видим, что синхронизация была выполнена.
И чтобы подтвердить, что данные действительно были отправлены на сервер, нам сначала нужно удалить наш запрос на получение из динамического кеша и нажать кнопку «ПОЛУЧИТЬ ДАННЫЕ».
Как работает JS: сервис-воркеры
Перед вами перевод восьмой части серии материалов об особенностях работы различных механизмов JavaScript. Сегодняшняя статья посвящена сервис-воркерам. Здесь мы рассмотрим их особенности, поговорим об их жизненном цикле, об их поддержке в браузерах, и о сценариях их использования.
Прогрессивные веб-приложения
Прогрессивные веб-приложения, по всей видимости, будут становиться всё популярнее и распространённее. Они нацелены на то, чтобы пользователь воспринимал их не как обычные веб-страницы, а как нечто вроде классических настольных приложений, которые нормально работают независимо от того, подключен компьютер к интернету или нет.
Отсюда исходит одно из основных требований к прогрессивным веб-приложениям, которое заключается в их надёжном функционировании при отсутствующем или нестабильном сетевом соединении. Сервис-воркеры являются важной технической деталью реализации подобного поведения приложений.
Приложение, сервис-воркер, кэш и сетевые ресурсы
Здесь вы можете видеть упрощённую схему взаимоотношений между приложением, сервис-воркером, кэшем, управлением которым занимается сервис-воркер, и сетевыми ресурсами. В идеале, правильная организация взаимодействия приложения с сервис-воркером и кэшем позволит пользователю нормально работать с приложением даже без подключения к сети.
Особенности сервис-воркеров
Если вы хотите как следует изучить сервис-воркеры, вам стоит взглянуть на предыдущий материал этой серии, который посвящён веб-воркерам. В целом можно сказать, что сервис-воркеры — это разновидность веб-воркеров, а если точнее, то они похожи на разделяемые воркеры. В частности, можно выделить следующие важные особенности сервис-воркеров:
Жизненный цикл сервис-воркера
Жизненный цикл сервис-воркера не имеет ничего общего с жизненным циклом веб-страницы. Он включает в себя следующие этапы:
▍Загрузка
▍Установка
Для того чтобы установить сервис-воркер, сначала его нужно зарегистрировать. Это делается в JavaScript-коде. Когда сервис-воркер зарегистрирован, браузеру предлагается запустить установку в фоновом режиме.
Метод register() можно без проблем вызывать каждый раз, когда загружается страница. Браузер самостоятельно выяснит, был ли уже зарегистрирован соответствующий сервис-воркер и правильно обработает повторный запрос на регистрацию.
В ходе процесса установки сервис-воркера рекомендуется загрузить и поместить в кэш статические ресурсы. После их кэширования установка веб-воркера будет успешно завершена. Если загрузка не удастся, автоматически будет сделана попытка повторной установки. В результате, после успешной установки веб-воркера, разработчик может быть уверен в том, что все необходимые статические материалы находятся в кэше.
Почему? Представим, что пользователь впервые открывает веб-приложение. В этот момент сервис-воркер для этого приложения пока не загружен, более того, браузер не может узнать заранее, будет ли приложение использовать сервис-воркер. Если сервис-воркер будет устанавливаться, браузеру понадобится потратить дополнительные системные ресурсы. Эти ресурсы в противном случае пошли бы на рендеринг веб-страницы. Как результат, запуск процесса установки сервис-воркера может отсрочить загрузку и вывод страницы. Обычно же разработчики стремятся к тому, чтобы как можно быстрее показать пользователю рабочую страницу приложения, но в нашем случае без сервис-воркера приложение не сможет нормально работать.
Обратите внимание на то, что вышеприведённые рассуждения имеют смысл только при разговоре о первом посещении страницы. Если, после установки сервис-воркера, пользователь снова посетит ту же страницу, повторная установка производиться не будет, а значит, не пострадает и скорость показа рабочей страницы. После первого посещения страницы приложения сервис-воркер будет активирован, в результате он сможет обрабатывать события загрузки и кэширования при последующих посещениях веб-приложения. Как результат, приложение будет готово к работе в условиях ограниченного сетевого соединения.
▍Активация
После установки сервис-воркера мы переходим к следующему этапу его жизненного цикла — к активации. На этом шаге у разработчика появляется возможность поработать с данными, которые были кэшированы ранее.
После активации сервис-воркер сможет управлять всеми страницами, которые попадают в его область видимости. Тут стоит отметить, что механизмы сервис-воркера не будут действовать на ту страницу, которая его зарегистрировала, до тех пор, пока эта страница не будет перезагружена.
После того, как сервис-воркер получит управление, он может оказаться в одном из следующих состояний:
Жизненный цикл сервис-воркера
Обработка процесса установки внутри сервис-воркера
Сервис-воркер, после того, как был запущен процесс его регистрации, способен воздействовать на происходящее. В частности, речь идёт об обработчике события install в коде сервис-воркера.
Вот что нужно сделать сервис-воркеру при обработке события install :
Если все материалы успешно кэшированы, это означает и успешную установку сервис-воркера. Если что-нибудь загрузить не удастся, тогда установка будет признана несостоявшейся. Поэтому следует обращать особое внимание на то, какие данные требуется поместить в кэш.
Тут надо отметить, что обработка события install внутри сервис-воркера необязательна.
Работа с кэшем в процессе выполнения приложения
Здесь начинается самое интересное. Именно тут мы разберём механизмы перехвата запросов, возврата кэшированных данных и кэширования новых материалов.
Вот что тут, в общих чертах, происходит:
Обновление сервис-воркера
Если имеется хотя бы мельчайшее различие между файлом сервис-воркера, который был загружен, и текущим файлом, браузер решит, что в коде воркера произошли изменения. Это означает, что в приложении должен использоваться новый сервис-воркер.
Зачем всё это нужно? Для того чтобы избежать проблемы наличия двух версий веб-приложения, выполняющихся одновременно, в разных вкладках браузера. Подобное, на самом деле, встречается весьма часто, и ситуация, в которой разные вкладки находятся под контролем разных веб-воркеров, способна привести к серьёзным ошибкам (например — к использованию различных схем данных при локальном хранении информации).
Удаление данных из кэша
При обработке события activate новой версии сервис-воркера, обычно занимаются работой с кэшем. В частности, тут удаляют старые кэши. Если сделать это раньше, на этапе установки нового воркера, старый сервис-воркер не сможет нормально работать.
Вот пример того, как можно удалить из кэша файлы, которые не были помещены в белый список (в данном случае белый список представлен записями page-1 и page-2 ):
Использование HTTPS
Сервис-воркер, который не защищён HTTPS, подвержен атакам посредника, так как злоумышленник сможет перехватывать соединения и создавать фальшивые ответы на запросы приложения. Именно поэтому, для того, чтобы сделать систему безопаснее, разработчик должен регистрировать сервис-воркеры на страницах, которые обслуживаются по HTTPS. В частности, это даёт уверенность в том, что сервис-воркер, загружаемый в браузер, не был модифицирован во время передачи его кода по сети.
Поддержка в браузерах
Пока ситуация с поддержкой сервис-воркеров браузерами не идеальна, но она улучшается:
Поддержка сервис-воркеров в браузерах
Тут можно наблюдать за процессом внедрения поддержки API сервис-воркеров в браузеры.
Сценарии использования
Сервис-воркеры открывают дорогу для замечательных возможностей веб-приложений. Вот некоторые из них:
Итоги
Сервис-воркеры — перспективная технология, являющаяся базой прогрессивных веб-приложений. Эту технологию, а так же её отдельные возможности, поддерживают пока не все браузеры, но у нас есть все основания ожидать улучшения ситуации. Поэтому вполне возможно, что в обозримом будущем таланты сервис-воркеров смогут полноценно раскрыться во всех ведущих браузерах, давая разработчикам новые инструменты и идеи.
Предыдущие части цикла статей:
Уважаемые читатели! Какие сценарии использования сервис-воркеров в ваших проектах кажутся вам наиболее интересными?
Использование Service Worker
В данной статье содержится информация о начале работы с сервис-воркерами, включая базовую архитектуру, процесс регистрации, а также установку и активацию новых сервис-воркеров, обновление существующих сервис-воркеров, управление кешем и настраиваемые ответы и все это в контексте простого приложения с офлайн-функциональностью.
Предпосылки появления Service Workers
Одной из важнейших проблем, от которой страдали пользователи веб-приложений, была работа в условиях потери связи. Лучшее в мире веб-приложение оставит ужасное впечатление от использования, если вы не сможете его загрузить. Предпринималось много попыток создания технологий, которые бы решили эту проблему, и если верить страницам нашего Форума, некоторые из вопросов были решены. Но всё же наиважнейшей проблемой по-прежнему является отсутствие хорошего механизма для управления кешем ресурсов и настраиваемыми сетевыми запросами.
Предыдущей попыткой была технология AppCache, казавшаяся хорошей идеей, потому как позволяла действительно просто указывать ресурсы для кеширования. Однако, эта технология допускает много предположений о том, что вы пытаетесь сделать, и затем с грохотом ломается, когда ваше приложение работает не в точности с этими допущениями. Чтобы получить больше информации по этой теме, прочитайте (неудачно названную, но хорошо написанную) статью Джейка Арчибальда Application Cache is a Douchebag.
На заметку: Начиная с Firefox 44, когда используется AppCache для предоставления странице поддержки офлайн-режима, в консоли разработчика отображается предупреждение о том, что нужно использовать технологию Service Workers (баг 1204581.)
Технология Service Workers должна в итоге решить озвученные выше вопросы. Синтаксис Service Worker более сложен, чем тот же AppCache, но взамен вы можете посредством JavaScript контролировать AppCache-подразумеваемое поведение с высокой степенью детализации, что позволяет вам решить описанную проблему и многие другие. Используя Service Worker, вы можете без труда получить приложение, использующее в первую очередь кешированные ресурсы, предоставляя тем самым поведение по умолчанию в автономном режиме, до того как будет получено по сети больше данных (такой подход называется Offline First). Так обычно работают нативные приложения, что часто является причиной выбора пользователя в их пользу.
Что нужно настроить, чтобы поиграть с Service Worker
Многие функции Service Worker теперь включены по умолчанию в новых браузерах, поддерживающих эту технологию. Однако, если вы обнаружите, что демонстрационный код не работает в вашей версии браузера, вам может понадобиться их включить:
Также вам необходимо предоставлять ваш код по протоколу HTTPS — Service Worker требует этого по соображениям безопасности. По этой причине GitHub — хороший выбор для экспериментов, поскольку он поддерживает протокол HTTPS по умолчанию. Для облегчения локальной разработки браузеры считают localhost также безопасным origin.
Базовая архитектура
Чтобы сделать базовую настройку Service Worker, как правило, нужно пройти следующие шаги:
Следующий рисунок кратко показывает доступные события Service Worker:
Промисы
Промисы — отличный механизм для запуска асинхронных операций, которые могут успешно зависеть друг от друга. Промисы имеют большое значение в работе сервис-воркеров.
Давайте сравним структуру традиционного синхронного колбэка с его промис-эквивалентом.
async
Вместо этого мы можем написать собственный промис для работы с подобными случаями. (Вы можете найти исходный код в нашем примере Promises test или взглянуть на живое демо.)
Все это происходит асинхронно.
На заметку: вы можете также объединять вызов нескольких промис-методов в одну цепочку, как в этом примере:
myPromise().then(success, failure).then(success).catch(failure);
На заметку: вы можете получить гораздо больше информации о промисах, прочитав превосходную статью Джейка Арчибальда (Jake Archibald’s) JavaScript Promises: there and back again.
Демонстрация Service Workers
Чтобы продемонстрировать только базовые моменты регистрации и установки сервис-воркеров, мы создали простое демо-приложение, названое sw-test. Это простая галерея изображений «Star wars Lego». Оно использует промис-функции, чтобы прочитать из JSON-объекта и загрузить, используя технологию Ajax, изображения, находящиеся далее нижнего края страницы, до того как они будут показаны. В приложении также ещё регистрируется, устанавливается и активируется сервис-воркер, и, в случае если браузер поддерживает спецификацию Service Worker, запрашиваемые ресурсы будут закешированы, и приложение будет работать в офлайн-режиме!
Вы можете посмотреть исходный код на GitHub, а также этот живой пример. Единственное, что мы тут рассмотрим, это промис (смотрите app.js строки 22-47), модифицированная версия того, о котором вы читали выше в разделе Тестовая демонстрация промисов. Разница в следующем:
Погружение в Service Worker
Итак, переходим к Service Worker!
Регистрация воркеров
Ниже представлен первый блок кода файла app.js. Это точка входа в Service Worker.
Предыдущий код регистрирует сервис-воркера, который работает в worker-контексте, и следовательно, не имеет доступа к DOM. Затем вы запускаете код в сервис-воркере, вне ваших страниц, чтобы контролировать их загрузку.
Один сервис-воркер может контролировать несколько страниц. Каждый раз, когда загружается страница, находящаяся в пределах области видимости, сервис-воркер будет установлен на ней и начнёт работу. Поэтому будьте осторожны с применением глобальных переменных в скриптах сервис-воркеров, потому как у каждой страницы нет своего уникального экземпляра сервис-воркера.
На заметку: Сервис-воркеры функционально похожи на прокси-серверы, они позволяют модифицировать запросы и ответы, замещая записями из собственного кеша, и многое другое.
На заметку: Есть одна очень хорошая особенность при работе с сервис-воркерами. В случае, если вы используете функциональность проверки поддержки Service Worker, то приложение в браузерах, не имеющих поддержки, продолжат нормально работать с ожидаемым поведением. Кроме того, если браузер поддерживает только AppCache, то будет использована эта технология. В случае, если браузер поддерживает и AppCache и Service Worker, то будет использована Service Worker.
Почему мой сервис-воркер не прошёл регистрацию?
Это может произойти по следующим причинам:
Также обратите внимание:
Установка и активация: заполнение кеша
После того как ваш сервис-воркер будет зарегистрирован, браузер может попробовать установить его и активировать на странице/сайте.
Событие install возникает после того как установка успешно завершится. Это событие используется главным образом для того, чтобы заполнить кеш браузера ресурсами, необходимыми для успешного запуска в офлайн-режиме. Для этого используется новый API хранилища Service Worker — cache — глобальный для всех сервис-воркеров, который позволяет нам хранить результаты запросов, используя в качестве ключа для их получения сами запросы. Этот API работает аналогично стандартному кешу браузера, но только для вашего домена. Данные в кеше сохраняются до тех пор, пока вы сами не решите их удалить — вы имеете полный контроль.
На заметку: Cache API поддерживается не всеми браузерами (смотрите раздел Browser support чтобы получить больше информации). Если вы хотите сейчас использовать эту технологию, то можете рассмотреть возможность использования полифила, который доступен в Google’s Topeka demo, или можете хранить ресурсы в IndexedDB.
Давайте начнём этот раздел посмотрев на фрагмент кода ниже — это первый блок кода, который вы увидите в нашем сервис-воркере:
На заметку : localStorage работает схожим образом, но в синхронном режиме, поэтому запрещён в сервис-воркерах.
На заметку : При необходимости хранить данные в сервис-воркерах вы можете использовать IndexedDB.
Настраиваемые ответы на запросы
Событие fetch возникает каждый раз, когда запрашиваются любые подконтрольные сервис-воркеру ресурсы, к которым относятся документы из области видимости и другие ресурсы, связанные с этими документами (например, если в index.html происходит кросс-доменный запрос для загрузки изображения, то он тоже попадёт в сервис-воркер).
Для начала, на каждый сетевой запрос мы можем отдать в ответ ресурс, чей url соответствует запросу:
caches.match(event.request) позволяет нам проверять сетевой запрос ресурса на соответствие какому-либо доступному в кеше ресурсу, если такой ресурс имеется. Соответствие проверяется по url и изменяемым заголовкам.
Давайте рассмотрим несколько других вариантов реализации нашей магии (чтобы получить больше информации об интерфейсах Request и Response смотрите документацию к Fetch API.)
Конструктор Response() позволяет вам создавать собственные ответы. В данном случае, мы всего лишь возвращаем простую текстовую строку:
В этом более сложном объекте Response показано, как вы можете передать набор заголовков в свой ответ, эмулируя стандартный HTTP-ответ. Здесь мы просто сообщаем браузеру, чем является содержимое ответа:
Если совпадение не было найдено в кеше, вы можете попросить браузер загрузить (en-US) тот же ресурс, чтобы получить новый файл через обычную сеть, если она доступна:
Если информация, соответствующая запросу, в кеше не найдена, а также сеть не доступна, то вы можете просто ответить на запрос какой-либо страницей по умолчанию, которая хранится в кеше, используя match() :
Восстановление неудачных запросов
Итак, caches.match(event.request) отработает как нужно только в том случае, если в кеше сервис-воркера будет найдено соответствие запросу. Но что произойдёт, если такого соответствия не будет найдено? Если мы не предоставим никакого механизма обработки такой ситуации, то промис выполнится со значением undefined и мы не получим никакого значения.
К счастью, сервис-воркеры имеют структуру основанную на промисах, что делает тривиальной такую обработку и предоставляет большое количество способов успешно обработать запрос:
Если промис будет отклонён, функция catch() вернёт обычный сетевой запрос к внешнему ресурсу. Это значит, что, если сеть доступна, то ресурс просто загрузится с сервера.
Если же мы были достаточно умны, то мы не стали бы просто возвращать сетевой запрос, а сохранили бы его результат в кеше, чтобы иметь возможность получить его в офлайн-режиме. В случае с нашим демо-приложением «Star Wars gallery», это означает, что, если в галерею будет добавлено ещё одно изображение, то оно будет получено и сохранено в кеше:
Почему? Потому что потоки запроса и ответа могут быть прочитаны только единожды. Чтобы ответ был получен браузером и сохранён в кеше, нам нужно клонировать его. Так оригинальный объект отправится браузеру, а клон будет закеширован. Оба они будут прочитаны единожды.
Обновление вашего сервис-воркера
Если после того, как ваш сервис-воркер был установлен, стала доступна его новая версия, при обновлении или загрузке страницы она будет установлена в фоновом режиме, но не будет активирована. Она будет активирована, лишь когда не останется ни одной страницы, использующей старую версию сервис-воркера.
Вы можете обновить обработчик события install в новой версии сервис-воркера, чтобы получить примерно такое (обратите внимание на номер новой версии):
В то время, как этот код работает, предыдущая версия также доступна. Новая версия устанавливается в фоновом режиме. Мы можем работать с версией кеша v2, в то время как версия v1 не будет разрушена.
Когда ни одна страница не будет использовать текущую версию, новый воркер активируется и станет ответственным за обработку всех запросов.
Удаление старого кеша
Вы можете обрабатывать событие activate. Оно обычно используется в случае, если нужно выполнить такие действия, которые бы нарушили работу воркеров предыдущей версии, если они все ещё работают со старым кешем. Также это событие полезно использовать для того, чтобы удалить ненужные данные, чтобы освободить место, занимаемое на диске, потому что каждый браузер имеет жёсткие ограничения на размер хранилища кеша, которое доступно для использования сервис-воркерами.
Инструменты разработчика
Firefox также начал реализовывать полезные инструменты для разработки сервис-воркеров: