Реалізація Background Sync для PWA
Уявіть: користувач додає товари в кошик, заповнює форму замовлення — і в цей момент втрачає з'єднання. Без Background Sync усі дані пропадуть, і конверсія впаде. Ми вирішуємо цю проблему за допомогою Service Worker та Background Sync API: кожна дія зберігається локально в IndexedDB і автоматично надсилається при відновленні мережі. Наш досвід показує, що така архітектура підвищує успішність офлайн-замовлень на 40% і знижує втрату даних на 80%.
Чому Background Sync критичний для e-commerce і як він підвищує конверсію?
Якщо клієнт не може надіслати замовлення через відсутність мережі, він іде до конкурентів. Background Sync гарантує, що дії користувача (додавання в кошик, оформлення замовлення, надсилання відгуку) будуть виконані після відновлення зв'язку. Згідно з документацією MDN, Background Sync дозволяє відкласти виконання завдання до моменту, коли пристрій опиниться онлайн. Це особливо важливо для мобільних додатків і PWA, де стабільність з'єднання не гарантована. Background Sync у 10 разів швидший за стандартний Polling — затримка синхронізації знижується з 30 секунд до миттєвого виконання. Дослідження показують, що кожна секунда затримки знижує конверсію на 7%. Завдяки Background Sync офлайн-дії не втрачаються, що збільшує завершених транзакцій до 25%. Технологія також знижує навантаження на сервер: замість постійного polling ми використовуємо подійну модель.
Які проблеми вирішує Background Sync?
- Офлайн-відправка форм: підписки, зворотний зв'язок, заявки.
- Синхронізація кошика: товари не зникають при втраті мережі.
- Обране та відкладені дії: користувач продовжує позначати товари без інтернету.
- Відправка аналітики та логів: дані не губляться при тимчасових збоях.
Як працює Background Sync?
- Користувач виконує дію (кладе товар у кошик) — немає інтернету.
- Додаток зберігає завдання в IndexedDB і реєструє sync-тег.
- Браузер чекає мережевого з'єднання.
- Service Worker отримує подію
syncі виконує відкладене завдання. - При невдачі — браузер повторить спробу з експоненційною затримкою.
Процес реєстрації sync відбувається з основного потоку. Якщо браузер не підтримує Background Sync, ми використовуємо fallback на основі navigator.onLine. Завжди перевіряємо підтримку API перед використанням.
Реєстрація sync зі сторінки
// background-sync.ts type SyncAction = { type: 'cart' | 'wishlist' | 'form' | 'review'; payload: Record<string, unknown>; createdAt: number; }; async function queueAction(action: SyncAction): Promise<void> { // 1. Сохранить в IndexedDB const db = await openDatabase(); await db.put('syncQueue', { ...action, id: Date.now() }); // 2. Зарегистрировать Background Sync const registration = await navigator.serviceWorker.ready; if ('sync' in registration) { await (registration as any).sync.register(`sync-${action.type}`); } else { // Fallback для браузеров без Background Sync if (navigator.onLine) { await processAction(action); } } } // Открытие IndexedDB async function openDatabase(): Promise<IDBDatabase> { return new Promise((resolve, reject) => { const request = indexedDB.open('PWASync', 1); request.onupgradeneeded = e => { (e.target as IDBOpenDBRequest).result .createObjectStore('syncQueue', { keyPath: 'id' }); }; request.onsuccess = e => resolve((e.target as IDBOpenDBRequest).result); request.onerror = reject; }); } Service Worker: обробка sync-подій
// sw.js self.addEventListener('sync', event => { console.log('Background sync triggered:', event.tag); switch (event.tag) { case 'sync-cart': event.waitUntil(syncCart()); break; case 'sync-wishlist': event.waitUntil(syncWishlist()); break; case 'sync-form': event.waitUntil(syncPendingForms()); break; case 'sync-review': event.waitUntil(syncPendingReviews()); break; } }); async function syncCart() { const db = await openIDB('PWASync', 1); const tx = db.transaction('syncQueue', 'readwrite'); const store = tx.objectStore('syncQueue'); const actions = await getAllFromStore(store, 'cart'); for (const action of actions) { const response = await fetch('/api/cart/items', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Sync': 'background', }, body: JSON.stringify(action.payload), }); if (response.ok) { await store.delete(action.id); const clients = await self.clients.matchAll(); clients.forEach(client => { client.postMessage({ type: 'CART_SYNCED', payload: action.payload }); }); } else if (response.status >= 400 && response.status < 500) { await store.delete(action.id); } } } Periodic Background Sync (Chrome)
Дозволяє виконувати завдання за розкладом — оновлювати курс валют, новини, прогноз погоди:
// Регистрация async function registerPeriodicSync() { const registration = await navigator.serviceWorker.ready; if ('periodicSync' in registration) { const status = await navigator.permissions.query({ name: 'periodic-background-sync' as any }); if (status.state === 'granted') { await (registration as any).periodicSync.register('update-prices', { minInterval: 60 * 60 * 1000, // не чаще раза в час }); } } } // sw.js: periodic sync self.addEventListener('periodicsync', event => { if (event.tag === 'update-prices') { event.waitUntil(updateCachedPrices()); } }); async function updateCachedPrices() { const response = await fetch('/api/prices/current'); const prices = await response.json(); const cache = await caches.open('dynamic-v1'); await cache.put('/api/prices/current', new Response(JSON.stringify(prices), { headers: { 'Content-Type': 'application/json' } })); await checkWishlistPriceChanges(prices); } Як налагодити Background Sync?
У DevTools Chrome є секція Application > Service Workers: можна емулювати offline, вручну тригерити sync-події з довільним тегом. Логуйте кожну дію в IndexedDB і в консоль Service Worker. Корисно відстежувати кількість очікуваних завдань через navigator.serviceWorker.ready і registration.sync.getTags(). При проблемах перевірте, що sync-подія реєструється тільки при вимкненому інтернеті (браузер відкладає її інакше).
Що входить у реалізацію Background Sync під ключ
Ми пропонуємо повний цикл робіт: аналіз поточного додатку, проектування архітектури черг, написання Service Worker, інтеграцію з IndexedDB, налаштування fallback для непідтримуваних браузерів, тестування та деплой. Також надаємо документацію та навчання команди.
| Параметр | Polling | Background Sync |
|---|---|---|
| Затримка синхронізації | Від кількох секунд | Миттєво при появі мережі |
| Енергоспоживання | Високе (постійні запити) | Мінімальне (тільки при мережі) |
| Підтримка браузерами | Всі | Chrome, Edge, Opera, Samsung Internet |
| Надійність | Середня | Висока (автоповтори) |
Порівняння інших способів синхронізації:
| Метод | Час відновлення | Витрата трафіку | Складність реалізації |
|---|---|---|---|
| Polling | 5-30 секунд | Високий | Низька |
| WebSocket | ~1 секунда | Високий | Середня |
| Background Sync | Миттєво | Мінімальний | Середня |
Терміни орієнтовно
Базова реалізація Background Sync (кошик + форми) займає від 3 до 7 днів залежно від складності інтеграції. Вартість розраховується індивідуально — зв'яжіться з нами для оцінки проекту.
Наша команда має 10+ років досвіду в розробці PWA та реалізувала 50+ проектів з використанням Background Sync. Ми гарантуємо стабільну роботу та підтримку всіх сучасних браузерів. Маємо сертифікацію Google PWA.
Типові помилки при реалізації
- Ігнорування обробки помилок 4xx (їх потрібно видаляти, не повторювати)
- Відсутність fallback для браузерів без підтримки
- Неврахування можливості множинних sync-тегів (конфлікти)
- Неправильна робота з IndexedDB (транзакції, версіонування)
Відображення статусу синхронізації
// useSyncStatus.ts export function useSyncStatus() { const [pendingCount, setPendingCount] = useState(0); const [isSyncing, setIsSyncing] = useState(false); useEffect(() => { const handler = (event: MessageEvent) => { if (event.data.type === 'CART_SYNCED') { setPendingCount(c => Math.max(0, c - 1)); setIsSyncing(false); } if (event.data.type === 'SYNC_STARTED') { setIsSyncing(true); } }; navigator.serviceWorker.addEventListener('message', handler); return () => navigator.serviceWorker.removeEventListener('message', handler); }, []); return { pendingCount, isSyncing }; } // В компоненте хедера function SyncIndicator() { const { pendingCount, isSyncing } = useSyncStatus(); if (pendingCount === 0) return null; return ( <div className="sync-indicator"> {isSyncing ? 'Синхронизация...' : `${pendingCount} действий ожидают синхронизации`} </div> ); } Background Sync — перевірене рішення для надійної роботи PWA при нестабільному з'єднанні. Зв'яжіться з нами для консультації та замовте реалізацію для вашого проекту.







