У цій статті я хотів би розповісти про Service Workers (SW). Програмне забезпечення дозволяє нам підготувати нашу програму в автономному режимі, щоб вона працювала, навіть якщо у нас немає підключення до Інтернету. Вони також дозволяють нам використовувати багато інших розширених функцій, як-от push-повідомлення або фонова синхронізація. Програмне забезпечення працює навіть після того, як ви закриєте браузер, тобто Service Worker продовжує працювати. Це фоновий процес. Тож давайте зареєструємо нашого першого сервісного працівника.
(У цій статті я реалізую функціональні можливості, пов’язані з програмним забезпеченням у звичайному JS, оскільки код написаний на звичайному JS, який ми можемо інтегрувати в будь-які фреймворки JS, такі як Angular, React або Vue)
Як перший крок, давайте додамо файл sw.js до кореневої папки проекту. У app.js ми повинні перевірити, чи доступний service worker в навігаторі, тобто чи підтримує service worker даний браузер. Тепер, оскільки ми знаємо, що сервісні працівники доступні, ми можемо виконати метод navigator.serviceWorker.register(), щоб зареєструвати нового сервіс-воркера, який вказує шлях до файлу, де знаходиться наш сервіс-воркер. Цей метод фактично повертає обіцянку. Тож, щоб отримати інформацію, коли це буде зроблено, ми можемо ланцюжком за ним.

Оскільки ми зареєстрували нашого першого сервісного працівника, давайте додамо нашого першого слухача подій. Як я вже говорив раніше, SW працюють у фоновому режимі. Але я не згадав про те, що всі вони обробляють події. Щоб приєднати прослуховувачі подій до сервіс-воркера, ми спочатку повинні посилатися на нього за допомогою ключового слова self, яке в основному означає «надати мені доступ до сервіс-воркера», а потім ми можемо виконати метод addEventListener(). У Service Worker ми маємо доступ до спеціального набору подій, наприклад, події встановлення, яка буде запущена, коли браузер встановить Service Worker. Там ми виконуємо функцію, отримуємо об’єкт події, який автоматично передається у функцію браузером, і цей об’єкт дає нам інформацію про подію встановлення. Як ми бачимо, наш сервісний працівник успішно встановлений.

Тепер ми можемо почати впроваджувати статичне кешування або попереднє кешування. Фаза встановлення Service Worker — чудове місце для кешування деяких активів, які не часто змінюються, як-от оболонка вашої програми або базовий стиль. У прослуховуванні подій встановлення ми пишемо кеші, щоб отримати доступ до API кешу, а потім метод open() передає ім’я нашого кешу. За допомогою цього ми відкриваємо там новий кеш. Але спочатку нам потрібно обернути цей вираз виразом event.waitUntil(). Він просто чекає, поки вся робота з кешуванням буде виконана. Це не дозволить завершити подію встановлення. У цьому блоці ми отримуємо доступ до цього кешу і тепер можемо додавати до нього вміст. Записуючи cache.addAll(), ми додаємо файли, які представляють оболонку нашої програми.

Тепер давайте подивимося, чи насправді ці файли завантажуються в кеш-пам’ять. І справді, вони є.

Наступним кроком ми повинні отримати файли з кешу, щоб наша програма могла працювати в автономному режимі. Давайте подивимося, як це зробити. Ще одна дуже важлива подія, яку ми також можемо прослухати, це подія fetch. Fetch запускатиметься щоразу, коли наш веб-додаток отримує щось, наприклад файли css та js або навіть запити xhr. Тож у прослуховувачі подій вибору сервіс-воркера давайте переконаємося, що ми дійсно отримуємо дані з нашого кешу. Спочатку я додам це рішення, а потім поясню, як воно працює.

Вираз event.respondWith() дозволяє нам перезаписати дані, які повертаються. Ви можете розглядати Service Worker як мережевий проксі, принаймні, якщо ми використовуємо тут подію fetch. Таким чином, кожен вихідний запит на вибірку проходить через сервіс-воркер, як і кожна відповідь. Тобто якщо ми нічого не робимо, відповідь просто передається, і ми не отримаємо жодної відповіді. Вираз cashes.match() дозволяє нам перевірити, чи даний запит уже кешовано. Якщо так, він поверне кешовану відповідь. Ми не робимо мережевий запит, ми перехоплюємо запит і не випускаємо новий, натомість ми просто дивимося на те, що ми хотіли запитати, і перевіряємо, чи є він у кеші та чи ми повертаємо його звідти. З іншого боку, якщо ми не знайдемо його в кеші, тоді ми хочемо повернути запит на вибірку, куди ми звертаємося, або де ми просто продовжуємо виконувати початковий запит, тому повертаємо fetch(event.request). Після всіх цих змін ми нарешті можемо використовувати наш веб-додаток в автономному режимі. Воля 🙂
Як бачите, наш веб-додаток містить діаграму з деякими статичними даними, і нічого не відбувається, коли ви натискаєте кнопку «ОТРИМАТИ ДАНІ». Тепер я хочу реалізувати, що після натискання цієї кнопки ми отримаємо деякі статистичні дані, відобразимо їх на діаграмі та збережемо ці дані в кеші. Таким чином ми реалізуємо динамічне кешування. Тож почнемо. Скажімо, у нас є кінцева точка, яка повертає статистичні дані про те, скільки користувачів відвідали наш підроблений сайт. Тож тепер ми повинні отримати ці дані та відобразити їх на діаграмі.


І, як і раніше, я збираюся додати рішення та пояснити, як воно працює.
Динамічне кешування просто означає, що ми все одно маємо подію вибору, і ми хочемо зберегти відповідь, яка повертається в наш кеш. Як і раніше, ми пишемо кеші, щоб отримати доступ до API кешу та метод open(), передаючи ім’я нашого кешу. Вираз cache.put() просто зберігає ваші дані. Першим аргументом, який ви передаєте, є URL-адреса запиту події, ідентифікатор. Другий аргумент – відповідь. Таким чином, ми зберігаємо точний клон, який є все, що нам потрібно, він містить усі дані відповіді, але ми повертаємо оригінальну відповідь. Це воно. Вперше ми захоплюємо статистичні дані з нашого сервера та зберігаємо їх у кеші. Вдруге ми заберемо ці дані з кешу. Це рішення чудово працює не тільки із запитами xhr. Наприклад, таким чином ми можемо динамічно кешувати файли css або навіть зображення.
Хуух, це було багато нової інформації.
До речі, і на додаток я хочу сказати кілька слів про фонову синхронізацію. Фонова синхронізація – це надсилання даних на сервер, коли у нас немає з’єднання з Інтернетом. Тож як це працює за лаштунками? Для реєстрації завдання синхронізації ми можемо використовувати сервіс-воркер. Тепер, звичайно, реєстрація завдання — це ще не все, що нам потрібно зробити, нам також потрібно зберігати дані, які ми хочемо надіслати разом із запитом, в індексованій базі даних. Отже, якщо у нас не було з’єднання і воно було відновлено, сервісний працівник негайно виконає це завдання. Так звана подія синхронізації буде виконана на service worker, і ми зможемо прослухати цю подію. Найцікавіше те, що це спрацює навіть, якщо ми закриємо вкладку або навіть браузер на мобільних телефонах. Тепер я хочу зареєструвати першу задачу синхронізації, і для цього я перш за все перевірю, чи є у нас доступ до сервісних працівників у даному браузері. Однак ми також повинні перевірити, чи доступний менеджер синхронізації у вікні. Менеджер синхронізації — це в основному API, за допомогою якого ми використовуємо функції фонової синхронізації. Потім я звернуся до свого сервісного працівника, і там я можу зателефонувати до властивості ready, щоб переконатися, що її налаштовано. Тож тепер ми можемо працювати з працівником сервісу. Щоб зареєструвати нове завдання синхронізації, ми маємо отримати доступ до властивості синхронізації (це дає нам доступ до менеджера синхронізації), і там ми можемо викликати метод register. Він приймає лише один аргумент, і це ідентифікатор, який ідентифікуватиме задане завдання синхронізації. Тому тут я дам йому назву «запит синхронізації». Пізніше ми використовуватимемо це ім’я в службі Worker, щоб реагувати на відновлене з’єднання та перевіряти, які невирішені завдання ми маємо, а потім можемо використовувати тег, щоб дізнатися, що нам потрібно зробити з цим завданням.
Тепер я хочу реалізувати, що після натискання кнопки «POST DATA» ми збережемо дані, які ми хочемо надіслати, в indexedDB та зареєструємо нове завдання синхронізації. Для цього, перш за все, ми повинні додати кілька додаткових файлів у наш проект, щоб легко працювати з indexedDB. Тоді давайте створимо дані, які ми хочемо зберегти. Це буде простий об’єкт з двома властивостями. Перша властивість — ідентифікатор. Друга властивість називається «неділя», значення якої дорівнює 10 (для повноти нашої діаграми :)) Для зберігання цих даних ми використовуємо допоміжну функцію під назвою writeData з utility.js, яка приймає два аргументи. Перший аргумент – це ім’я бази даних, яку будуть зберігати дані, а другий – самі наші дані. Після успішного виконання ми реєструємо нове завдання синхронізації.
І нарешті ми підійшли до найцікавішої частини – прослуховування події синхронізації та відповідної реакції на відновлене з’єднання. І, як і раніше, я збираюся додати рішення та пояснити, як воно працює.
Спочатку ми повинні перевірити тег події. Тоді я використовую event.waitUntil(), як і раніше, це просто дозволяє мені переконатися, що подія не закінчиться превентивно. Потім ми отримуємо дані, які ми зберегли в indexedDB (за допомогою допоміжної функції з utility.js), перебираємо їх, надсилаємо запит на публікацію для кожного з фрагментів даних, які будуть збережені, а потім видаляємо їх із indexedDB, якщо ми успішно відправили їх на сервер . Це все. Давайте зараз спробуємо це. Щоб перевірити цю функціональність, ми повинні перейти в автономний режим у нашому браузері, натиснути кнопку «Опублікувати дані», а потім знову підключитися до Інтернету.
Після натискання кнопки «Опублікувати дані», коли ми в автономному режимі, нічого не відбувається, але коли з’єднання відновлено, ми бачимо, що синхронізацію виконано.
І щоб підтвердити, що дані дійсно надіслано на сервер, нам спочатку потрібно видалити наш запит на отримання з динамічного кешу та натиснути кнопку «ОТРИМАТИ ДАНІ». Воля 🙂
Наразі все, хлопці. Побачимось. Мій код доступний на github: GitHub – Draakan/simplePWA