Практическая работа №9: Service Workers и IndexedDB
Цель работы: Научиться использовать Service Worker для кэширования ресурсов и обеспечения офлайн-доступа, а также применять IndexedDB для локального хранения данных в браузере. По итогам работы студент должен уметь регистрировать Service Worker, перехватывать сетевые запросы, сохранять данные в IndexedDB, реализовывать простой офлайн-сценарий веб-приложения и имитировать синхронизацию данных.
Основные теоретические положения
Section titled “Основные теоретические положения”1. Что такое Service Worker?
Section titled “1. Что такое Service Worker?”Service Worker — это JavaScript-файл, который работает в фоновом режиме браузера, отдельно от основного потока выполнения веб-страницы. Он действует как программный прокси-сервер между браузером и сетью, позволяя перехватывать сетевые запросы, управлять кэшем и обеспечивать офлайн-функциональность. Service Worker не имеет прямого доступа к DOM, но может взаимодействовать со страницей через механизм обмена сообщениями (postMessage) и события.
Жизненный цикл Service Worker:
- Регистрация (Registration): Браузер скачивает и регистрирует файл Service Worker.
- Установка (Installation): Вызывается событие
install. На этом этапе обычно происходит предварительное кэширование статических ресурсов (HTML, CSS, JS, изображения). - Активация (Activation): Вызывается событие
activate. Здесь обычно происходит очистка старых кэшей, оставшихся от предыдущих версий Service Worker. - Работа (Fetch/Message): Service Worker готов перехватывать сетевые запросы (событие
fetch) или получать сообщения от страницы.
Пример регистрации Service Worker:
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => { console.log('ServiceWorker успешно зарегистрирован в области:', registration.scope); }) .catch(error => { console.log('Ошибка регистрации ServiceWorker:', error); }); });}2. Что такое IndexedDB?
Section titled “2. Что такое IndexedDB?”IndexedDB — это встроенная в браузер низкоуровневая объектная база данных для хранения значительных объёмов структурированных данных на стороне клиента. В отличие от localStorage (который хранит только строки и имеет жесткие ограничения по объему), IndexedDB:
- Поддерживает транзакции для обеспечения целостности данных.
- Позволяет создавать индексы для быстрого поиска.
- Работает асинхронно, не блокируя основной поток выполнения (UI).
- Может хранить сложные объекты JavaScript (например, файлы, Blob).
Основные понятия IndexedDB:
- База данных (Database): Контейнер для хранилищ объектов.
- Хранилище объектов (Object Store): Аналог таблиц в реляционных БД. Хранит данные в виде пар “ключ-значение”.
- Транзакция (Transaction): Оболочка вокруг операций чтения/записи. Гарантирует, что операции будут выполнены целиком или не выполнены вообще.
- Курсор (Cursor): Механизм для перебора записей в хранилище.
Пример открытия базы данных:
const request = indexedDB.open('MyDatabase', 1);
request.onupgradeneeded = (event) => { const db = event.target.result; // Создаем хранилище объектов, если оно не существует if (!db.objectStoreNames.contains('notes')) { db.createObjectStore('notes', { keyPath: 'id', autoIncrement: true }); }};
request.onsuccess = (event) => { const db = event.target.result; console.log('База данных успешно открыта');};
request.onerror = (event) => { console.error('Ошибка при открытии базы данных:', event.target.error);};3. Стратегии кэширования
Section titled “3. Стратегии кэширования”При перехвате запросов в Service Worker можно использовать различные стратегии:
- Cache First (Сначала кэш): Сначала проверяется кэш. Если ресурс найден, он возвращается. Если нет — делается запрос в сеть, результат кэшируется и возвращается. Идеально для статических ресурсов (картинки, CSS, шрифты).
- Network First (Сначала сеть): Сначала делается запрос в сеть. Если он успешен, ответ кэшируется и возвращается. Если сети нет, берется резервная копия из кэша. Подходит для часто обновляемых данных.
- Stale While Revalidate (Устаревшее при обновлении): Немедленно возвращается закэшированная версия, а в фоновом режиме делается запрос в сеть для обновления кэша.
Алгоритм выполнения работы
Section titled “Алгоритм выполнения работы”1. Подготовка проекта и окружения
Section titled “1. Подготовка проекта и окружения”- Создайте папку проекта, например
pwa_lab/. - Подготовьте базовые файлы:
index.html— разметка страницы.app.js— основной скрипт приложения (регистрация SW, работа с UI и IndexedDB).sw.js— скрипт Service Worker (должен лежать в корне проекта).styles.css— стили для интерфейса.
- Важно: Service Worker работает только по протоколу HTTPS или на
localhost. Для локальной разработки используйте локальный сервер (например,python3 -m http.server 8000или расширение Live Server в VS Code). Открытие файла черезfile://не позволит зарегистрировать Service Worker.
2. Задания для выполнения
Section titled “2. Задания для выполнения”Выполняйте задания последовательно. Для каждого пункта пишите код и проверяйте его работоспособность в браузере (используйте DevTools: вкладки Console, Application -> Service Workers, Application -> IndexedDB, Application -> Cache Storage).
Часть 1: Регистрация Service Worker и кэширование ресурсов
Section titled “Часть 1: Регистрация Service Worker и кэширование ресурсов”- Регистрация: В файле
app.jsнапишите код для регистрации Service Worker (sw.js). Выведите в консоль или на страницу статус регистрации. - Установка и кэширование: В файле
sw.jsобработайте событиеinstall. Создайте кэш с именемpwa-cache-v1и добавьте в него основные файлы:/,/index.html,/app.js,/styles.css.- Подсказка: Используйте
event.waitUntil()иcaches.open().
- Подсказка: Используйте
- Активация и очистка: Обработайте событие
activate. Напишите логику, которая удаляет все кэши, имя которых не совпадает с текущим (pwa-cache-v1). - Перехват запросов (Cache First): Обработайте событие
fetch. Реализуйте стратегию Cache First: при запросе ресурса сначала ищите его в кэше (caches.match()). Если он там есть — верните его. Если нет — выполните сетевой запрос (fetch()). - Офлайн-заглушка: Измените логику
fetchтак, чтобы при отсутствии сети (ошибкаfetch) и запросе HTML-страницы возвращался простой текстовый ответ или заранее закэшированная страница-заглушка с сообщением “Вы находитесь в офлайн-режиме”. - Статус сети: В
app.jsдобавьте слушатели событийonlineиofflineна объектwindow. При изменении статуса обновляйте индикатор на странице (например, зеленый кружок “Online” и красный “Offline”).
Часть 2: Работа с IndexedDB
Section titled “Часть 2: Работа с IndexedDB”В файле app.js (или отдельном db.js) реализуйте функции для работы с базой данных.
- Инициализация БД: Напишите функцию
initDB(), которая открывает базу данныхoptimization_labверсии 1. - Создание хранилища: В обработчике
onupgradeneededсоздайте объектное хранилищеnotes.- Настройки хранилища:
keyPath: 'id',autoIncrement: true. - Создайте индекс по полю
createdAt:objectStore.createIndex('createdAt', 'createdAt', { unique: false }).
- Настройки хранилища:
- Добавление данных: Напишите функцию
addNote(note), которая принимает объект заметки и сохраняет его в хранилищеnotesс использованием транзакцииreadwrite. - Чтение данных: Напишите функцию
getNotes(), которая возвращает все записи из хранилища (используйте методgetAll()). - Удаление данных: Напишите функцию
deleteNote(id), которая удаляет запись по еёid. - Тестовые данные: При успешном открытии пустой базы данных (проверьте количество записей), автоматически добавьте следующие тестовые данные для проверки:
{ title: "Купить продукты", content: "Молоко, хлеб, яйца, сыр", createdAt: new Date().toISOString() }{ title: "Подготовиться к экзамену", content: "Повторить лекции по PWA и IndexedDB", createdAt: new Date().toISOString() }{ title: "Позвонить заказчику", content: "Обсудить макеты нового сайта", createdAt: new Date().toISOString() }
Часть 3: Интеграция интерфейса и офлайн-сценарий
Section titled “Часть 3: Интеграция интерфейса и офлайн-сценарий”- Отображение данных: Напишите функцию
renderNotes(notes), которая принимает массив заметок и отрисовывает их на странице (например, в виде карточек или таблицы). Каждая заметка должна иметь кнопку “Удалить”. - Форма добавления: Создайте в
index.htmlформу с полями “Заголовок” и “Текст заметки”. При отправке формы вызывайтеaddNote(), затем обновляйте список заметок на странице. - Проверка офлайн-работы:
- Откройте приложение в браузере. Убедитесь, что тестовые данные загрузились.
- Перейдите в DevTools -> Network и включите режим “Offline”.
- Перезагрузите страницу. Приложение должно загрузиться из кэша Service Worker, а данные должны успешно прочитаться из IndexedDB.
- Попробуйте добавить новую заметку в офлайн-режиме. Она должна сохраниться в IndexedDB и отобразиться на странице.
Часть 4: Имитация фоновой синхронизации (Background Sync)
Section titled “Часть 4: Имитация фоновой синхронизации (Background Sync)”Поскольку стандартный Background Sync API поддерживается не всеми браузерами, мы реализуем его упрощенную ручную версию.
- Очередь синхронизации: В
onupgradeneededсоздайте еще одно хранилище объектовsyncQueue(сautoIncrement: true). - Логика сохранения: Измените функцию добавления заметки. Если
navigator.onLineравноfalse(нет сети), сохраняйте заметку не только вnotes, но и вsyncQueue. - Синхронизация при появлении сети: В обработчике события
online(которое срабатывает при восстановлении связи) напишите логику:- Прочитать все записи из
syncQueue. - Вывести в консоль сообщение:
Синхронизация данных с сервером: [данные]. (В реальном приложении здесь был быfetchPOST-запрос на сервер). - После “успешной отправки” очистить хранилище
syncQueue.
- Прочитать все записи из
- Индикатор: Добавьте на страницу счетчик “Ожидают синхронизации: N”, который показывает количество записей в
syncQueue.
Контрольные вопросы
Section titled “Контрольные вопросы”- Что такое Service Worker и чем он отличается от обычного JavaScript-кода на странице?
- Какие события жизненного цикла Service Worker вы использовали и зачем они нужны?
- Что такое Cache Storage и как он помогает ускорить приложение?
- Чем стратегия Cache First отличается от Network First? В каких случаях какую лучше применять?
- Что такое IndexedDB и чем она отличается от
localStorage? - Как создаётся объектное хранилище в IndexedDB? Что такое
keyPath? - Зачем нужны транзакции в IndexedDB? Какие режимы транзакций существуют?
- Почему Service Worker не может напрямую управлять DOM страницы?
- Какие ограничения есть у офлайн-режима веб-приложения?
- Как работает механизм синхронизации данных, реализованный в Части 4?
Критерии оценки
Section titled “Критерии оценки”- 30% — Корректная регистрация Service Worker, кэширование статических ресурсов и успешная загрузка приложения в офлайн-режиме.
- 30% — Правильная работа с IndexedDB: создание базы, инициализация тестовыми данными, добавление, чтение и удаление записей.
- 20% — Интеграция с пользовательским интерфейсом, корректное отображение статуса сети (Online/Offline).
- 10% — Реализация механизма очереди синхронизации (
syncQueue). - 10% — Оформление кода (разделение на функции, использование
async/awaitилиPromise, обработка ошибокtry/catch), читаемость интерфейса и полные ответы на контрольные вопросы.
Рекомендуемая структура файлов
Section titled “Рекомендуемая структура файлов”index.html
Section titled “index.html”- Заголовок лабораторной работы.
- Индикатор статуса сети (Online/Offline) и счетчик синхронизации.
- Форма добавления заметки (input для заголовка, textarea для текста, кнопка).
- Контейнер (div или table) для вывода списка заметок.
app.js
Section titled “app.js”- Регистрация Service Worker.
- Логика работы с IndexedDB (открытие, добавление, чтение, удаление).
- Вставка тестовых данных при первом запуске.
- Обработчики событий для формы и кнопок удаления.
- Слушатели событий
onlineиofflineдля обновления интерфейса и запуска синхронизации.
- Массив
ASSETSс путями к кэшируемым файлам. - Обработчик
install: открытие кэша иcache.addAll(). - Обработчик
activate: удаление старых версий кэша. - Обработчик
fetch: стратегия Cache First с резервным ответом для офлайна.
Рекомендуемая литература и ресурсы
Section titled “Рекомендуемая литература и ресурсы”- MDN Web Docs: Service Worker API [1]
- MDN Web Docs: Использование IndexedDB [2]
- web.dev: Service workers and the Cache Storage API [3]
- JavaScript.info: IndexedDB [4]
- Google Developers: The Offline Cookbook (Стратегии кэширования) [5]
Дополнительное задание (для досрочно выполнивших основную часть)
Section titled “Дополнительное задание (для досрочно выполнивших основную часть)”- Добавьте поле поиска, которое фильтрует отображаемые заметки по заголовку (используйте методы массивов JavaScript после получения данных из БД).
- Реализуйте возможность редактирования существующей заметки (метод
putв IndexedDB). - Добавьте кнопку “Очистить кэш и БД”, которая удаляет базу данных (
indexedDB.deleteDatabase()) и очищает Cache Storage, после чего перезагружает страницу. - Подготовьте краткий отчёт (в виде Markdown-файла) о том, как Service Worker влияет на скорость повторной загрузки приложения (сравните время загрузки с включенным и отключенным SW через вкладку Network в DevTools).