- 1.Вступ
- 2.Проблема
- 3.Як це працює, або офлайн-робота
- 4.Як це все може працювати разом?
- 5.Що потрібно знати перед роботою з Service Worker?
- 6.Спілкування з вебсторінками
- 7.Безпека
- 8.Налаштування офлайн-роботи
- 9.Інші можливості
- 10.Фонова синхронізація
- 11.Push-повідомлення
- 12.Перехоплення та модифікація мережевих запитів
- 13.Висновок
Чи чули ви колись про офлайн вебдодатки, або офлайн вебсайти? Я впевнений що так, а якщо не чули, то зараз ще й дізнаєтесь, як і чому це працює та кому потрібно.
У назві цієї статті присутня назва технології про яку йтиме мова далі, тобто Service Workers, але перед тим, як ми зануримось у подробиці реалізації та використання, з'ясуймо, яку проблему вирішує саме ця технологія.
ПРОБЛЕМА
Уявімо собі ситуацію, насправді на момент написання цієї статті я якраз знаходжусь у такій ситуації, тому це перше, що прийшло мені на думку. Отже, ви пишете статтю про Service Workers, а для написання використовуєте сервіс Google Docs, адже це так зручно.
Під час написання тексту в Google Docs, ви розумієте, що у вас зникло підключення до інтернету, причини можуть бути різні, але ситуація така. Ви вже починаєте хвилюватися, що потрібно швидко зберегти текст кудись в інше місце, щоб не втратити його. Й випадково перезавантажуєте сторінку і думаєте: «Ну все, вся робота втрачена». Але на ваше здивування, сторінка перезавантажується, весь текст, котрий ви писали, залишається на своєму місці й ви навіть можете продовжити свою роботу далі, адже все працює. Не зрозуміло як, але працює.
ЯК ЦЕ ПРАЦЮЄ, АБО ОФЛАЙН-РОБОТА
Офлайн робота вебдодатка зазвичай реалізується через такий інструмент як Service Worker.
Service Worker — це спеціальний скрипт, що працює у фоновому режимі та не залежить від сторінки, на якій знаходиться користувач. Це фоновий скрипт, тому він може працювати та виконувати операції й тоді, коли користувач не переглядає вебсайт.
Загалом офлайн робота сайту в будь-якому випадку буде базуватися на кешуванні ресурсів і контенту сайту: це одна з задач, які виконує Service Worker. Є й інші, а саме: пуш-нотифікації та оновлення даних у фоновому режимі (незалежно від сторінки чи контексту).
Кешування — процес зберігання копій даних у тимчасовому сховищі, відомому як кеш. Цей процес дозволяє швидко отримати доступ до цих даних при наступних запитах. У контексті веброзробки, кешування зазвичай використовується для зберігання вебресурсів, таких як HTML-сторінки, стилі CSS, JavaScript-файли, зображення тощо, щоб вони могли бути швидко завантажені без необхідності повторного звернення до сервера.
Я вже декілька разів вказав на те, що Service Worker працює в фоновому режимі та не залежить від поточного контексту. Насправді цей скрипт виконується в окремому, унікальному контексті. Контекст, у якому виконується Service Worker є ізольованим від основного потоку виконання, він (Service Worker) не має доступу до DOM дерева й виконується повністю асинхронно.
Сучасні вебдодатки та вебсайти постійно комунікують із сервером, зазвичай синхронні й асинхронні запити. Рідше, але також доволі часто, це комунікація через вебсокети.
ЯК ЦЕ ВСЕ МОЖЕ ПРАЦЮВАТИ РАЗОМ?
Як додаткам, які базуються на постійній роботі з сервером працювати в офлайн режимі? Відразу хочу зробити наголос на тому. що в будь-якому випадку це буде обмежена робота.
Річ у тім, що окрім кешування даних, Service Workers можуть перехоплювати мережеві запити, модифікувати їх, або брати відповідь зі збережених у кеш даних. Здається, що процес роботи досить простий, але є досить багато стратегій кешування даних, які можуть бути досить складними в реалізації.
Хотілося б відзначити механізм фонового оновлення даних. Цей механізм має великий, або навіть критичний вплив на вебдодаток, який працює офлайн. Тож, як ми вже знаємо, Service Worker не має доступу до багатьох звичних нам API сторінки, тому що працює в ізольованому контексті. Але має доступ до API кешування (caches) і до API мережевих запитів (fetch). Як ви вже зрозуміли, якраз за допомогою fetch API й відбувається синхронізація даних з сервером, коли зʼявляється підключення до мережі (зʼявляється інтернет).
ЩО ПОТРІБНО ЗНАТИ ПЕРЕД РОБОТОЮ З SERVICE WORKER?
Окрім того, що було написано вище, (ізоляція, кешування, контроль мережевих запитів), перед початком роботи з Service Workers потрібно розуміти наступні речі.
ЖИТТЄВИЙ ЦИКЛ
Реєстрація. Робота з Service Worker завжди починається з реєстрації скрипта Service Worker на сторінці. Це робиться наступним чином:
navigator.serviceWorker.register(‘шлях до файлу Service Worker.js’, { scope: ‘/scope/’ })
Також, за допомогою другого аргументу функції можна задати область дії Service Worker.
Встановлення. Після етапу реєстрації Service Worker переходить на стадію встановлення, під час якої виконується подія ‘install’. Зазвичай, саме в цей момент відбувається кешування статичних ресурсів (HTML, CSS, JS і т. д.), потрібних для офлайн-роботи додатка.
Активація. Після закінчення події install Service Worker переходить до стадії активації, під час якої відбувається подія ‘activate’. Одне з головних завдань, яке потрібно виконати — це видалення старого кешу, який уже був створений раніше, для вивільнення місця і запобігання конфліктів між різними версіями кешованих даних.
Перехоплення мережевих запитів. Вище ми вже говорили про те, що Service Worker має можливість перехоплювати мережеві запити, модифікувати їх або віддавати кешовані дані. Важливо розуміти, що мова йде як про запити на дані, так і про запити на статичні ресурси: HTML, CSS, JavaScript, медіафайли. Після перехоплення запитів, за допомогою caches API актуальні дані можуть бути закешовані. Тобто, логіка наступна: якщо сервер нам відповідає даними, то ми можемо їх закешувати, а якщо сервер відповідає помилкою, або запит на сервер не може бути відправлений через проблеми з мережею — дістати з кешу дані, які були туди додані раніше й використати їх.
Оновлення. Коли вебсторінка завантажується, браузер автоматично перевіряє, чи існує оновлена версія файлу Service Worker за тим самим шляхом. Якщо файл Service Worker був змінений, браузер завантажує його. Після цього відбуваються події які описані вище, а саме: встановлення й активація. у цьому випадку, Service Worker буде оновлено тільки після того, як усі сторінки, які були відкриті та працювали під старою версією Service Worker, будуть закриті.
Нагадаю, Service Worker працює у фоновому режимі в окремому контексті, який не пов'язаний з контекстом сторінки, тому процес саме такий. Важливо розуміти, що процес оновлення потрібно ретельно тестувати, для того, щоб він спрацював саме так, як вам потрібно.
Видалення. Коли активується нова версія Service Worker, то стара версія видаляється, таким чином відбувається перехід між версіями. Хочу зазначити, що під час видалення старої версії Service Worker рекомендується видаляти кеш, пов'язаний з тою версією.
СПІЛКУВАННЯ З ВЕБСТОРІНКАМИ
Хоч, як і було сказано раніше, Service Workers працюють в ізольованому контексті й не мають доступу до DOM дерева, все ж вони можуть спілкуватися зі сторінкою за допомогою іншого механізму. Цей механізм називається postMessage API, він не є унікальним для Service Workers, також використовується для реалізації спілкування JavaScript коду з іншими сутностями.
БЕЗПЕКА
Безпека Service Workers ґрунтується на примусовому використанні HTTPS для запобігання перехоплення і модифікації коду й даних. Важливо уважно ставитися до обробки мережевих запитів і відповідей, щоб запобігти вставці шкідливого коду. Також необхідно регулярно оновлювати й перевіряти Service Workers, щоб уникнути зловмисного використання застарілих кешованих даних чи застарілих стратегій кешування.
НАЛАШТУВАННЯ ОФЛАЙН-РОБОТИ
Зверніть увагу, після кожного прикладу я додав посилання на github репозиторій з повною реалізацією функціоналу.
Реєструємо Service Worker
Для початку, нам потрібно зареєструвати наш Service Worker у JavaScript файлі який підключений до сторінки. Назвемо його: main.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js')
.then(function(registration) {
// Реєстрація успішна
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// Реєстрація провалилася
console.log('ServiceWorker registration failed: ', err);
});
});
}
Створення Service Worker
Створимо файл service-worker.js, де будемо описувати логіку його роботи.
const CACHE_NAME = 'v1';
const urlsToCache = [
'/',
'/styles/main.css',
'/scripts/main.js'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
У цьому коді:
- install подія використовується для відкриття кешу й додавання початкового набору файлів до кешу;
- fetch подія перехоплює мережеві запити. Якщо запитуваний ресурс знаходиться в кеші, він повертається з кешу, інакше він завантажується з мережі.
Важливо розуміти, що це тільки базовий приклад роботи.
ІНШІ МОЖЛИВОСТІ
Насправді налаштування офлайн-роботи Service Worker має ряд інших можливостей, таких як:
- фонова синхронізація — синхронізація даних поки додаток не активний;
- push-повідомлення — можливість відправлення push-повідомлень, коли користувач не переглядає сайт;
- перехоплення і модифікація мережевих запитів — гнучке керування мереживими запитами й генерація відповідей на них.
Розглянемо ці можливості на прикладах.
ФОНОВА СИНХРОНІЗАЦІЯ
У цьому прикладі я надам тільки декілька файлів демонстраційного проєкту. Повний проєкт можна знайти в моєму GitHub репозиторії, посилання буде нижче.
scripts/sync.js — тут міститься логіка для обробки форми й реєстрації фонової синхронізації.
document.getElementById('syncForm').addEventListener('submit', function(event) {
event.preventDefault();
const data = {
message: document.getElementById('dataInput').value
};
// Збереження даних в локальному сховищі
localStorage.setItem('syncData', JSON.stringify(data));
// Реєстрація події синхронізації
if ('serviceWorker' in navigator && 'SyncManager' in window) {
navigator.serviceWorker.ready
.then(function(swRegistration) {
return swRegistration.sync.register('sync-data');
})
.catch(function() {
// Відправка даних відразу, якщо фонова синхронізація недоступна
sendData(data);
});
} else {
// Фонова синхронізація не підтримується
sendData(data);
}
});
function sendData(data) {
// Код для відправлення даних на сервер
}
service-worker.js — додавання обробника фонової синхронізації до Service Worker.
self.addEventListener('sync', function(event) {
if (event.tag === 'sync-data') {
event.waitUntil(
// Отримання даних з локального сховища
localforage.getItem('syncData').then(function(data) {
return fetch('/path-to-your-api', {
method: 'POST',
body: JSON.stringify(data),
headers: { 'Content-Type': 'application/json' }
});
}).then(function(response) {
return response.json();
}).then(function(data) {
console.log('Дані успішно синхронізовані:', data);
// Видалення даних з локального сховища після успішної синхронізації
localforage.removeItem('syncData');
}).catch(function(err) {
console.error('Помилка під час синхронізації:', err);
})
);
}
});
НОТАТКИ
- У цьому прикладі використовується localforage для зберігання даних, які потрібно синхронізувати. Вам потрібно буде включити бібліотеку localforage у ваш проєкт.
- Функція sendData у scripts/sync.js має містити логіку для відправлення даних на сервер.
PUSH-ПОВІДОМЛЕННЯ
Аналогічно попередньому прикладу, в цьому прикладі будуть тільки основні файли для реалізації push-повідомлень, повну версію проєкту ви знайдете нижче.
scripts/push.js — логіка для підписки на push-повідомлення.
document.getElementById('subscribe').addEventListener('click', function() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(function(registration) {
registration.pushManager.subscribe({
userVisibleOnly: true,
// Використовуйте власний веб-ключ для push-повідомлень
applicationServerKey: 'YOUR_WEB_PUSH_KEY'
}).then(function(subscription) {
console.log('User is subscribed:', subscription);
}).catch(function(err) {
console.log('Failed to subscribe the user: ', err);
});
});
}
});
service-worker.js — додавання обробника для push-повідомлень.
self.addEventListener('push', function(event) {
const options = {
body: 'Це push-повідомлення!',
icon: 'images/icon.png',
badge: 'images/badge.png'
};
event.waitUntil(
self.registration.showNotification('Push Notification', options)
);
});
НОТАТКИ
- Ви маєте згенерувати власний вебключ для push-повідомлень, який буде використовуватись у applicationServerKey в scripts/push.js.
- Для використання push-повідомлень вам також потрібно буде налаштувати backend-сервер, який відправлятиме push-повідомлення до підписаних користувачів.
ПЕРЕХОПЛЕННЯ ТА МОДИФІКАЦІЯ МЕРЕЖЕВИХ ЗАПИТІВ
Аналогічно попередньому прикладу, в цьому прикладі будуть тільки основні файли для реалізації функціоналу перехоплення та модифікація мережевих запитів, повну версію проєкту ви знайдете нижче.
scripts/main.js — скрипт, що робить запит до сервера.
document.addEventListener('DOMContentLoaded', function() {
fetch('/data')
.then(function(response) {
return response.text();
})
.then(function(data) {
document.getElementById('content').innerText = data;
})
.catch(function(err) {
console.error('Помилка:', err);
});
});
service-worker.js — Service Worker, який перехоплює запити.
self.addEventListener('install', function(event) {
self.skipWaiting();
});
self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim());
});
self.addEventListener('fetch', function(event) {
if (event.request.url.endsWith('/data')) {
event.respondWith(
new Response('Це відповідь, змінена Service Worker!')
);
}
});
ЦІКАВЕ
- Стратегії кешування у Service Workers використовуються для забезпечення швидшого доступу до ресурсів вебдодатка, зменшення навантаження на сервери й забезпечення роботи додатка при обмеженому або відсутньому інтернет-з'єднанні. Це підвищує продуктивність вебдодатка й поліпшує загальний досвід користувача.
- Станом на 2023 рік, Service Workers мають широку підтримку у більшості сучасних веббраузерів. Загальна підтримка Service Workers у всьому світі складає приблизно 97,31%
ВИСНОВОК
Отже, ми досить глибоко занурились у світ Service Workers. Сподіваюся, ви зрозуміли, наскільки це крутий інструмент та чому його варто використовувати. Ці інструменти дозволяють вашому вебдодатку чи сайту витримувати випробування офлайн-режимом, вміють працювати з кешем, надсилати пуш-повідомлення й навіть керувати мережевими запитами.
Знаєте, в сучасному світі, де швидкість і доступність інформації мають велике значення, Service Workers — це справжній порятунок. Маючи їх у вашому арсеналі, ви можете створити додаток, який не тільки швидко працює та має круту функціональність, але й може витримувати виклики нестабільного інтернет-з'єднання.
На цьому закінчимо, сподіваюсь інформація була зрозумілою і корисною.