Реалізація Background Sync для PWA

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

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

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація Background Sync для PWA
Середня
~2-3 робочих дні
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація Background Sync для PWA

Background Sync дозволяє Service Worker виконати відкладене дію (відправити форму, синхронізувати дані) при відновленні соединення — навіть якщо користувач уже закрив вкладку.

Як працює Background Sync

  1. Користувач виконує дію (кладе товар у кошик) — немає інтернету
  2. Приложення зберігає завдання в IndexedDB та реєструє sync-тег
  3. Браузер чекає мережевого з'єднання
  4. Service Worker отримує подію sync та виконує відкладене завдання
  5. При неудачі — браузер повторює з експоненціальною задержкою

Реєстрація 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);
        }
        // 5xx — залишити для повтора (браузер повторить sync автоматично)
    }
}

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);
}

Відображення статусу синхронізації

// useSyncStatus.ts
export function useSyncStatus() {
    const [pendingCount, setPendingCount] = useState(0);
    const [isSyncing, setIsSyncing] = useState(false);

    useEffect(() => {
        // Слухати сообщення від Service Worker
        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>
    );
}

Час реалізації: 1–2 дні для базового Background Sync з кошиком та формами.