Доброго времени суток, друзья!
Вероятно, многие из вас слышали о таком новшестве в экосистеме JavaScript, как сервис-воркеры (Service Workers), которые являются ключевым элементом современной веб-разработки. Сервис-воркеры становятся все более востребованными, в первую очередь, благодаря популярности прогрессивных веб-приложений (Progressive Web Applications — PWA).
Когда я впервые услышал о них, я задался вопросом: «Когда мы должны использовать сервис-воркеры? В каким сценариях или контексте мы можем их использовать?»
В данной статье мы рассмотрим несколько практических примеров использования сервис-воркеров, что впоследствии, смею надеяться, сделает счастливыми ваших пользователей.
Полагаю, прежде чем разбирать практические примеры, необходимо хотя бы в общих чертах рассмотреть теоретические основы работы сервис-воркеров. Для начинающих разработчиков это послужит хорошим подспорьем в дальнейших начинаниях.
Что есть сервис-воркер?
Серсис воркер — это скрипт, запускаемый браузером в фоновом процессе. Помните, что сервис-воркер совершенно не зависит от страницы, с которой он взаимодействует или которой он служит (to serve — служить).
По сути, сервис-воркер представляет собой прокси сервер между веб-приложением, браузером и сетью.
Сервис-воркеры позволяют веб-приложениям работать подобно нативным приложениям.
Несколько фактов о сервис-воркерах
- Сервис-воркеры не имеют прямого доступа к DOM. Для этого они используют механизм ответов на запросы через интерфейс postMessages.
- Сервис-воркеры принудительно отменяются (останавливаются), когда не используются. Это означает, что они управляются с помощью событий.
- Сервис-воркеры предполагают использование обещаний (промисов).
- Ввиду больших возможностей сервис-воркеры могут использоваться только через HTTPS. На локальном сервере можно обойтись без HTTPS.
Как сервис-воркеры работают? Беглый взгляд
Сервис-воркеры позволяют перехватывать запросы к серверу и кешировать эти запросы с целью повышения производительности приложений. Таким образом, повышение производительности обеспечивается благодаря кешированию всего контента.
Но лучше один раз увидеть, так что вот вам изображение, показывающее работу сервис-воркера:
Жизненный цикл сервис-воркера
Как я упоминал ранее, сервис-воркеры работают независимо от управляющей страницы. Если вы хотите установить сервис-воркер в своем приложении, первым делом нужно его зарегистрировать.
После этого браузер, запустивший установку сервис-воркера, переходит в фоновый режим:
Самые распространенные случаи использования
Теперь, когда мы знаем, как работают сервис-воркеры, настало время поговорить о том, где они используются.
Кеширование
Как отмечалось выше, сервис-воркеры могут использоваться для кеширования. Вот некоторые примеры:
- Только кеширование — у вас есть статический контент, который никогда не меняется.
- Сеть или кеш — вы хотите показывать пользователям актуальный контент с условием быстрой загрузки.
- Кеш и обновление — вы хотите отображать контент мгновенно и не возражаете против периодической синхронизации с сервером.
- Кеш, обновление и перезагрузка — вы хотите показывать контент максимально быстро, подспудно обновляя отдельные его части и отображая их каким-либо «бесшовным» способом.
Веб-пуш (Web Push)
Веб-пуш позволяет приложениям отправлять пуш-уведомления и отображать контент, получаемый в ответ на эти уведомления.
- Пуш и обновление контента — вы хотите обмениваться (доставлять и получать) доступным контентом.
- Пуш и контент — вы хотите оперировать не только текстом, но также информацией других видов, обогащающей ваши сообщения.
- Насыщенный пуш- вы хотите показывать изображения, процесс загрузки и другие штуки, улучшающие сообщение, которое вы хотите доставить.
- Пуш и клиент — вы хотите показывать уведомления в зависимости от состояния приложения.
Более сложные примеры использования
API аналитики
У меня есть приложение. И я хочу добавить в него возможность следить за использованием приложения. Для этого я беру синхронное API для обновления собранных данных время от времени.
Балансировщик загрузки
Допустим, вы хотите иметь возможность выбирать лучшего провайдера контента, опираясь на показатели работы сервера. В этом случае вам нужен сервис-воркер для перехвата запросов и осуществления выбора.
Я настоятельно рекомендую вам посетить ServiceWorke.rs для более подробного изучения сервис-воркеров.
Отрабатываем навыки
Как я всегда говорю: «Хочешь научиться плавать — лезь в воду». Изучение теории — вещь замечательная, но пока не испачкаешь руки, ничему не научишься.
Регистрация сервис-воркера
Если мы вновь обратимся к иллюстрации жизненного цикла сервис-воркера, то увидим, что перво-наперво нам необходимо его установить. Чтобы это сделать нам нужно его зарегистрировать.
// проверяем поддержку браузером
if('serviceWorker' in navigator){
console.log('Сервис-воркер поддерживается')
// осуществляем регистрацию после загрузки страницы
// для этого добавляем обработчик события "load"
window.addEventListener('load', () => {
// регистрируем сервис-воркер
navigator.serviceWorker
.register('/service-worker.js')
.then(registration => {
// регистрация прошла успешно
console.log(`Сервис-воркер успешно зарегистрирован, scope: ${registration.scope}`) // scope - подмножество контента, которое находится под контролем сервис-воркера
})
})
.catch(error => {
// регистрация провалилась
console.log(`В процессе регистрация возникла ошибка: ${error}`)
})
}
В работе сервис-воркера можно убедиться, перейдя по адресу: Chrome://inspect/#service-workers.
Также информацию о состоянии сервис воркера можно получить в инструментах разработчика: Application -> Service Workers.
Что дальше?
Теперь нам нужно закешировать все файлы. Мы можем выбирать файлы для кеширования. Вот как это выглядит:
// название кеша
const CACHE_NAME = 'example.com-v1'
// выбираем файлы для кеширования
const cacheAssets = ['index.html', 'about.html', 'js/main.js']
// добавляем обработчик события "install"
self.addEventListener('install', e => {
console.log('Сервис-воркер установлен')
e.waitUntil(
caches
.open(CACHE_NAME)
.then(cache => {
console.log('Сообщение от сервис-воркера: файлы кешируются')
cache.addAll(cacheAssets)
})
.then(() => {
self.skipWaiting()
})
)
})
Вот что здесь происходит:
- Определяем название кеша (example.com-v1).
- Выбираем файлы для кеширования. Для этого создаем массив.
- Внутри обработчика события «install» велим браузеру ожидать завершения промиса, затем открываем кеш, который будет сохранен под именем «example.com-v1».
- Наконец, добавляем выбранные файлы в кеш.
Удаляем неиспользуемый кеш
Далее нам необходимо удалить старые версии кеша:
// добавляем обработчик события "activate"
self.addEventListener('activate', e => {
console.log('Сервис-воркер активирован')
e.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cache => {
if(cache !== CACHE_NAME){
console.log('Производится удаление старого кеша')
return caches.delete(cache)
}
})
)
})
)
})
Получение ответа
Ничто из приведенного выше не имеет смысла, если у нас нет возможности получить закешированный контент.
Его можно получить с помощью обработчика события «fetch»:
// добавляем обработчик события "fetch"
self.addEventListener('fetch', e => {
e.respondWith(
fetch(e.request)
.then(res => {
const copyCache = res.clone()
caches.open(CACHE_NAME).then(cache => {
cache.put(e.request, copyCache)
})
return res
})
.catch(error => caches.match(e.request).then(res => res))
)
})
Весь код можно посмотреть здесь.
Благодарю за внимание.