Чи знаєте ви про “Сервісних працівників” в JavaScript?

pic

Сервісні працівники (Service Workers) - це справжня революція в веб-розробці, дозволяючи розробникам створювати швидкі, надійні веб-додатки з підтримкою офлайн-режиму. Наприклад, інтернет-магазин може використовувати Сервісні працівники для кешування даних про продукти, що дозволяє користувачам переглядати та переглядати продукти навіть без підключення до інтернету. Вони працюють як проксі між браузером і мережею, надаючи повний контроль над мережевими запитами та стратегіями кешування.

У цьому блозі ми детально розглянемо Сервісні працівники, від їх основ до просунутих варіантів використання, і створимо To-Do App, яка демонструє операції CRUD, використовуючи Сервісні працівники для офлайн-здатності та покращення продуктивності.

Що таке Сервісні працівники?

Сервісний працівник (Service Worker) — це скрипт, який працює у фоновому режимі, окремо від основного потоку браузера. Він дозволяє реалізувати такі функції:

  1. Підтримка офлайн-режиму: Кешування активів і відповідей API для використання без інтернет-з’єднання.
  2. Push-повідомлення: Надсилання оновлень користувачам, навіть коли додаток не відкритий.
  3. Фоновий синхронізація: Забезпечення надійної синхронізації даних.
  4. Оптимізація ресурсів: Ефективне кешування та надання ресурсів.

Життєвий цикл Сервісного працівника

Розуміння життєвого циклу Сервісного працівника є важливим для розробників, оскільки він визначає, як і коли обробляються стратегії кешування, оновлення ресурсів та мережеві запити. Сервісні працівники мають специфічний життєвий цикл з трьох основних етапів: встановлення, активація та отримання.

  1. Встановлення: Під час етапу встановлення Сервісний працівник завантажується, і спрацьовує подія install. Саме тут зазвичай кешуються статичні активи, необхідні для роботи додатка в офлайн-режимі. Якщо встановлення проходить успішно, Сервісний працівник переходить до наступного етапу. Однак якщо якась частина процесу встановлення не вдається (наприклад, файл не вдалося кешувати), Сервісний працівник не активується.
  2. Активація: Після завершення встановлення Сервісний працівник переходить до етапу активації. Спрацьовує подія activate, і саме тут розробники можуть управляти старими кешами або виконати очищення, щоб переконатися, що додаток використовує актуальні ресурси. Тільки один Сервісний працівник може контролювати сторінку одночасно, і новий активований Сервісний працівник візьме на себе контроль, коли стане активним.
  3. Отримання: Після активації Сервісний працівник починає перехоплювати та обробляти мережеві запити через подію fetch. Цей етап критично важливий для реалізації стратегій кешування, таких як надання кешованих активів, отримання оновлених ресурсів із сервера або навіть управління контентом за замовчуванням, коли користувач перебуває в офлайн-режимі.

Розуміння та використання цього життєвого циклу дозволяє розробникам ефективно управляти оновленнями, оптимізувати продуктивність і забезпечити безперервний досвід для користувачів.

  1. Встановлення (install): Кешування статичних активів і налаштування Сервісного працівника.
  2. Активація (activate): Очищення старих кешів і підготовка Сервісного працівника до роботи.
    3.
    Fetch (fetch): Перехоплення і відповідь на мережеві запити.

pic

Створення To-Do додатка з використанням Сервісних працівників

Щоб продемонструвати можливості Сервісних працівників, ми створимо повністю функціональний To-Do додаток з CRUD операціями (створення, читання, оновлення, видалення) та підтримкою офлайн-режиму.

Крок 1: Налаштування проекту

Створіть наступні файли:

  • index.html
  • styles.css
  • script.js
  • service-worker.js

Крок 2: Реалізація HTML

<html>
  <head>
    <title>To-Do App</title>
  </head>
  <body>
    <h1>To-Do App</h1>
    <form id="todo-form">
      <input type="text" id="todo-input" placeholder="Add a new task" />
      <button type="submit">Add</button>
    </form>
    <ul id="todo-list"></ul>
  </body>
</html>

Крок 3: Стилізація додатка

/* styles.css */
body {
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 20px;
  background-color: #f4f4f9;
}
h1 {
  text-align: center;
  color: #333;
}
form {
  display: flex;
  justify-content: center;
  margin-bottom: 20px;
}
input {
  padding: 10px;
  font-size: 16px;
  flex: 1;
}
button {
  padding: 10px;
  font-size: 16px;
  background-color: #007bff;
  color: #fff;
  border: none;
  cursor: pointer;
}
button:hover {
  background-color: #0056b3;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: flex;
  justify-content: space-between;
  background: #fff;
  padding: 10px;
  margin-bottom: 10px;
  border: 1px solid #ddd;
}
li button {
  background: red;
  color: white;
  border: none;
  padding: 5px 10px;
  cursor: pointer;
}

Крок 4: Додавання JavaScript

/* script.js */
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js')
    .then(() => console.log('Сервісний працівник успішно зареєстровано'))
    .catch((err) => console.error('Не вдалося зареєструвати сервісний працівник:', err));
}

let id = new Date().getTime();
const form = document.getElementById('todo-form');
const input = document.getElementById('todo-input');
const list = document.getElementById('todo-list');

let todos = [];

// Функція для отримання завдань з кешу або сервера
async function fetchTodos() {
  try {
    const response = await fetch('/api/todos');
    todos = await response.json();
    updateCache(todos);
  } catch (err) {
    console.log('Офлайн: Завантаження кешованих завдань.');
    const cache = await caches.open('todo-cache');
    const cachedResponse = await cache.match('/api/todos');
    if (cachedResponse) {
      todos = await cachedResponse.json();
    }
  }
  renderTodos();
}

function updateCache(data) {
  caches.open('todo-cache').then((cache) => {
    const response = new Response(JSON.stringify(data));
    cache.put('/api/todos', response);
  });
}

function renderTodos() {
  list.innerHTML = '';
  todos.forEach((todo, index) => {
    const li = document.createElement('li');
    li.textContent = todo.text;
    const deleteButton = document.createElement('button');
    deleteButton.textContent = 'Delete';
    deleteButton.onclick = () => deleteTodoFromServer(todo.id);
    if (todo.completed) {
      li.style.textDecoration = 'line-through';
    }
    li.appendChild(deleteButton);
    list.appendChild(li);
}

async function addTodoToServer(text) {
  const todo = {
    text,
    id: id++,
    completed: false,
  };

  todos.push(todo);
  updateCache(todos);
  renderTodos();
  try {
    const response = await fetch('/api/todos', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(todo),
    });
    const savedTodo = await response.json();
    todo.id = savedTodo.id;
    updateCache(todos);
  } catch (err) {
    console.error('Error while saving todo:', err);
  }
}

} catch (err) {
  console.log('Офлайн: Завдання буде синхронізовано після підключення до мережі.');
}

async function deleteTodoFromServer(id) {
  todos = todos.filter((todo) => todo.id !== id);
  updateCache(todos);
  renderTodos();
  try {
    await fetch(`/api/todos/${id}`, { method: 'DELETE' });
  } catch (err) {
    console.log('Офлайн: Видалення буде синхронізовано після підключення до мережі.');
  }
}

form.addEventListener('submit', (e) => {
  e.preventDefault();
  addTodoToServer(input.value);
  input.value = '';
});

fetchTodos();

Крок 5: Сервісний працівник для підтримки офлайн-режиму

Використовуйте скрипт сервісного працівника для кешування ресурсів додатка та забезпечення роботи додатка в офлайн-режимі.

/* service-worker.js */
const CACHE_NAME = 'todo-app-v1';
const STATIC_ASSETS = [
  '/',
  '/index.html',
  '/styles.css',
  '/script.js',
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.addAll(STATIC_ASSETS);
    })
  );
});

self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames.map((cache) => {
          if (cache !== CACHE_NAME) {
            return caches.delete(cache);
          }
        })
      );
    })
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((cachedResponse) => {
      if (cachedResponse) {
        fetch(event.request).then((response) => {
          caches.open(CACHE_NAME).then((cache) => {
            cache.put(event.request, response.clone());
          });
        }).catch(() => {});
        return cachedResponse;
      }
      return fetch(event.request).then((response) => {
        return caches.open(CACHE_NAME).then((cache) => {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    })
  );
});

pic

Тестування додатка

1.
Запуск локального сервера: Використовуйте простий HTTP сервер, такий як http-server або live-server, щоб обслуговувати ваші файли.
2. Встановлення сервісного працівника: Відкрийте браузер і перевірте сервісного працівника в інструментах розробника.
3. Перехід в офлайн: Вимкніть інтернет і перевірте функціональність додатка в офлайн-режимі.

Розширені теми по сервісним працівникам

1. Фоновий синхронізатор

Фоновий синхронізатор дозволяє сервісному працівникові повторно спробувати неуспішні мережеві запити, коли мережа знову стане доступною. Це особливо корисно для забезпечення того, щоб такі дії, як відправка форм або оновлення даних, завершувалися успішно, навіть після тимчасових проблем з підключенням.

self.addEventListener('sync', (event) => {
  if (event.tag === 'sync-todos') {
    event.waitUntil(syncTodos());
  }
});

async function syncTodos() {
  const unsyncedTodos = await getUnsyncedTodosFromDB();
  for (const todo of unsyncedTodos) {
    try {
      await fetch('/api/todos', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(todo),
      });
      markTodoAsSynced(todo.id);
    } catch (err) {
      console.error('Помилка синхронізації:', err);
    }
  }
}

2. Push-сповіщення

Сервісні працівники дозволяють веб-додаткам надсилати push-сповіщення користувачам, навіть коли додаток не активний. Це вимагає інтеграції з сервісом push і обробки подій push у сервісному працівнику.

self.addEventListener('push', (event) => {
  const data = event.data.json();
  event.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: '/icon.png',
    })
  );
});

3. Періодична фонові синхронізації

Періодична фонові синхронізації дозволяють сервісному працівникові отримувати оновлені дані з сервера через певні проміжки часу. Ця функція поки що експериментальна, але обіцяє бути корисною для додатків, які потребують оновлення без взаємодії з користувачем.

navigator.serviceWorker.ready.then((registration) => {
  registration.periodicSync.register({ tag: 'fetch-latest-data', minInterval: 24 * 60 * 60 * 1000 }); // Синхронізація щодня
});

4. Поради з налагодження сервісних працівників

Налагодження сервісних працівників може бути складним через їх асинхронну природу. Ось кілька порад:

  • Використовуйте вкладку Application в інструментах розробника Chrome для перевірки реєстрацій сервісних працівників та кешів.
  • Додавайте значущі логи до кожного прослуховувача подій (Event Listener), щоб відстежувати хід операцій.
  • Тестуйте оновлення, скасовуючи реєстрацію та повторно реєструючи сервісного працівника, щоб переконатися, що активна остання версія.

Висновок

Сервісні працівники надають розробникам можливість створювати надійні веб-додатки, які підтримують офлайн-режим. Основні функції включають підтримку офлайн-режиму через кешування, перехоплення та оптимізацію мережевих запитів, а також покращення досвіду користувача через фонову синхронізацію та push-сповіщення. Використовуючи ці функції, розробники можуть створювати надійні високопродуктивні додатки, які залишаються функціональними в різних мережевих умовах. У цьому блозі ми розглянули основи сервісних працівників, їх життєвий цикл і побудували повністю функціональний додаток To-Do, демонструючи операції CRUD з підтримкою офлайн-режиму. Ви можете значно покращити продуктивність і надійність вашого веб-додатка, впроваджуючи сервісних працівників.

Перекладено з: Do you know Javascript “Service Workers”?

Leave a Reply

Your email address will not be published. Required fields are marked *