Service Workers як вони працюють і чому без них немає офлайн-режиму

Оновлено:
Service Workers як вони працюють і чому без них немає офлайн-режиму

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

Якщо ти вже читав повний гід по PWA, то знаєш що Service Worker — це один з трьох китів Progressive Web App поряд із Web App Manifest та HTTPS. Але що відбувається всередині — як він реєструється, перехоплює запити, зберігає кеш і переживає оновлення — більшість туторіалів пропускає.

У цій статті — технічний розбір від реєстрації до стратегій кешування. З кодом, типовими пастками і поясненням чому деякі речі працюють саме так, а не інакше.

📚 Зміст статті

Що таке Service Worker — і чим він відрізняється від звичайного JS

Звичайний JavaScript — це код, який живе разом із сторінкою. Він маніпулює DOM, реагує на кліки, відправляє запити. Коли сторінка закривається — він зникає разом із нею.

Service Worker — інша річ. Він запускається в окремому потоці (worker thread), повністю ізольованому від основного потоку сторінки (main thread). Це означає три важливих наслідки:

  • Немає доступу до DOM. Service Worker не може читати або змінювати HTML-елементи сторінки. Він живе поза нею.
  • Може жити після закриття сторінки. Браузер може "будити" Service Worker для фонових задач — синхронізації даних або отримання push-сповіщень — навіть коли жодна вкладка сайту не відкрита.
  • Спілкується через postMessage. Якщо Service Worker потрібно передати щось на сторінку або навпаки — вони обмінюються повідомленнями через postMessage(), як два окремих процеси.

Main thread vs Worker thread — в чому різниця

Main thread — це єдиний потік, де виконується весь JavaScript сторінки, відбувається рендеринг, обробляються події. Якщо щось важке запустити в main thread — сторінка "зависне".

Worker thread — окремий потік, який не блокує UI. Service Worker — це спеціалізований тип Web Worker, заточений під мережеві запити і кешування. На відміну від звичайного Web Worker, він має доступ до Cache API та PushManager і може жити незалежно від сторінки.

Важлива деталь: Service Worker є event-driven. Він не виконується постійно — він "прокидається" у відповідь на певні події (fetch, push, sync) і "засинає" після їх обробки. Це рішення браузера для економії ресурсів.

Де Service Worker "живе" фізично

Service Worker — це окремий JavaScript-файл, зазвичай sw.js, який знаходиться в кореневій директорії сайту або в папці з певним scope. Браузер реєструє його, завантажує і виконує незалежно від основного коду сторінки.

Архітектура виглядає так:

[Сторінка / Main App]

↕ (postMessage)

[Service Worker]

↕ ↕

[Cache API] [Мережа / Сервер]

Коли сторінка робить запит (наприклад, завантажує CSS або звертається до API), браузер спочатку "питає" Service Worker — що робити з цим запитом. Service Worker вирішує: повернути з кешу, піти в мережу або зробити щось комбіноване.

Lifecycle — Register → Install → Activate → Waiting

Lifecycle Service Worker — найбільш плутана тема для тих, хто починає з ним працювати. Розберемо кожен етап і типові помилки на кожному.

Етап 1: Register

Реєстрація відбувається в коді сторінки. Ти кажеш браузеру: "є такий файл sw.js, заберегистрируй його як Service Worker для цього origin".

Якщо браузер вперше бачить цей SW або файл змінився — починається процес встановлення. Якщо файл не змінився (навіть на один байт) — браузер нічого не робить, використовує вже активний SW.

Типова помилка: зареєструвати SW після умови або в блоці try/catch без обробки помилки. Якщо реєстрація впала тихо — ти ніколи не дізнаєшся.

Етап 2: Install

Після реєстрації браузер завантажує файл SW і запускає подію install. Тут зазвичай кешуються критичні ресурси — HTML-оболонка, CSS, JS, іконки.

Типова помилка: не чекати завершення кешування через event.waitUntil(). Якщо не передати проміс у waitUntil — браузер не знатиме коли install закінчився і може перейти до активації до того як кеш наповнений.

Етап 3: Waiting (найпопулярніша пастка)

Після успішного install новий Service Worker не стає активним одразу. Він чекає у стані waiting, поки старий SW звільнить усі відкриті вкладки сайту.

Чому так? Браузер захищає стабільність сесії. Якщо б новий SW активувався поки стара вкладка відкрита — стратегія кешування могла б змінитися посеред сесії користувача. Це могло б зламати роботу застосунку.

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

Рішення — skipWaiting():

self.addEventListener('install', event => {

self.skipWaiting(); // примусово активуємось, не чекаємо

event.waitUntil(

caches.open('my-app-v2').then(cache => {

return cache.addAll(['/index.html', '/app.css', '/app.js']);

})

);

});

Додай також clients.claim() в activate — щоб вже відкриті вкладки одразу перейшли під контроль нового SW:

self.addEventListener('activate', event => {

event.waitUntil(self.clients.claim());

});

Етап 4: Active

Коли старий SW звільнив усі вкладки (або ти примусово викликав skipWaiting()) — новий SW стає активним. З цього моменту він перехоплює всі fetch-запити сторінки.

В події activate прийнято чистити старі версії кешу — ті, що залишились від попередніх SW:

const CACHE_NAME = 'my-app-v2';

self.addEventListener('activate', event => {

event.waitUntil(

caches.keys().then(keys =>

Promise.all(

keys

.filter(key => key !== CACHE_NAME) // видаляємо все крім поточної версії

.map(key => caches.delete(key))

)

).then(() => self.clients.claim())

);

});

Важливо: версіонуй назву кешу при кожному деплої. Якщо залишати ту саму назву — старий контент залишиться в кеші після оновлення. Детальніше про цю пастку — у статті 8 критичних помилок при інтеграції PWA.

Реєстрація Service Worker — перший робочий код

Реєстрація відбувається один раз в основному JavaScript-коді сторінки. Ось мінімальний робочий приклад:

// main.js або inline в HTML

if ('serviceWorker' in navigator) {

window.addEventListener('load', () => {

navigator.serviceWorker

.register('/sw.js') // шлях до файлу SW

.then(registration => {

console.log('SW зареєстровано, scope:', registration.scope);

})

.catch(error => {

console.error('Помилка реєстрації SW:', error);

});

});

}

Розберемо кожну частину:

  • 'serviceWorker' in navigator — перевірка підтримки браузером. Якщо браузер не підтримує SW — код просто не виконається, сайт продовжить працювати без офлайн-можливостей.
  • window.addEventListener('load', ...) — чекаємо повного завантаження сторінки перед реєстрацією. Це запобігає конкуренції за ресурси між першим завантаженням і SW.
  • .register('/sw.js') — шлях до файлу SW. Зверни увагу: шлях починається з кореня. Scope SW за замовчуванням — директорія, де знаходиться файл sw.js.

Що таке scope і чому він важливий

Scope визначає які URL-запити буде перехоплювати Service Worker. За замовчуванням — це директорія файлу SW.

// sw.js знаходиться в корені — перехоплює ВСІ запити сайту

navigator.serviceWorker.register('/sw.js');

// scope = 'https://example.com/'

// sw.js знаходиться в /app/ — перехоплює тільки /app/*

navigator.serviceWorker.register('/app/sw.js');

// scope = 'https://example.com/app/'

// можна вказати scope явно

navigator.serviceWorker.register('/sw.js', { scope: '/shop/' });

// перехоплює тільки /shop/*

Неправильний scope — одна з причин чому SW "не перехоплює" запити. Якщо файл SW знаходиться в /js/sw.js — він за замовчуванням перехоплює тільки /js/*, а не весь сайт.

HTTPS — обов'язкова умова

Service Worker працює тільки через HTTPS. Це не рекомендація — це технічне обмеження браузера. Без HTTPS navigator.serviceWorker.register() просто не спрацює.

Єдиний виняток — localhost для розробки. На локальному сервері HTTPS не потрібен.

Якщо твій CDN або піддомен для статики працює через HTTP — SW не зможе кешувати ресурси з нього. Детально ця проблема розібрана в статті про 8 типових помилок PWA.

Cache API і Fetch event — як SW перехоплює запити

Чому не localStorage

Перше питання яке виникає: чому для кешування в SW використовується Cache API, а не звичний localStorage?

Відповідь проста: localStorage є синхронним і доступний тільки в main thread. Service Worker живе в окремому потоці і не має до нього доступу. Cache API — це асинхронний, Promise-based інтерфейс, спроєктований саме для worker-контексту.

Cache API також значно більш ємний (сотні мегабайт проти 5–10 МБ у localStorage), підтримує зберігання повних HTTP-відповідей з заголовками і добре підходить для кешування файлів.

Як працює Cache API

// Відкриваємо (або створюємо) кеш з іменем

const cache = await caches.open('my-app-v2');

// Додаємо файли до кешу

await cache.addAll([

'/',

'/index.html',

'/app.css',

'/app.js',

'/icons/icon-192.png'

]);

// Або додаємо один файл

await cache.add('/fonts/main.woff2');

// Отримуємо закешований ресурс

const response = await caches.match('/app.css');

// Видаляємо кеш

await caches.delete('my-app-v1');

Ключ у Cache API — це URL запиту. Кожен ресурс ідентифікується своєю адресою. Тому якщо URL змінився — він вважається новим ресурсом.

Fetch event — серце Service Worker

Коли будь-яка сторінка в scope SW робить мережевий запит — браузер генерує подію fetch у Service Worker. Саме тут відбувається вся логіка: взяти з кешу, піти в мережу, або комбінація.

self.addEventListener('fetch', event => {

// event.request — об'єкт запиту (URL, метод, заголовки)

// event.respondWith() — перехоплюємо запит і повертаємо відповідь

event.respondWith(

caches.match(event.request).then(cached => {

if (cached) {

return cached; // є в кеші — повертаємо одразу

}

return fetch(event.request); // немає — йдемо в мережу

})

);

});

event.respondWith() — це ключовий метод. Він каже браузеру: "не роби звичайний мережевий запит, я сам поверну відповідь". Якщо не викликати respondWith() — браузер піде в мережу як зазвичай.

Важливо: respondWith() потрібно викликати синхронно в обробнику події, але може приймати проміс, який резолвиться пізніше.

Service Workers як вони працюють і чому без них немає офлайн-режиму

Стратегії кешування — яку вибрати для свого проєкту

Не існує єдиної правильної стратегії кешування. Вибір залежить від типу контенту і того, що важливіше: свіжість даних чи швидкість і офлайн-доступ. Ось чотири основні стратегії з кодом:

СтратегіяКоли використовуватиСвіжість даних
Cache FirstСтатичні assets (CSS, шрифти, іконки)Низька — завжди з кешу
Network FirstAPI, динамічний контент, HTML-сторінкиВисока — спочатку мережа
Stale While RevalidateНовини, блог, аватариСередня — з кешу + оновлення фоном
Cache OnlyОфлайн-fallback, pre-cached ресурсиТільки кеш, мережа не використовується

Cache First

Спочатку дивимось у кеш, тільки якщо нема — йдемо в мережу. Ідеально для ресурсів, які рідко змінюються.

self.addEventListener('fetch', event => {

event.respondWith(

caches.match(event.request).then(cached => {

return cached || fetch(event.request).then(response => {

// Зберігаємо нову відповідь у кеш

return caches.open('static-v2').then(cache => {

cache.put(event.request, response.clone());

return response;

});

});

})

);

});

Network First

Спочатку йдемо в мережу, якщо недоступна — повертаємо з кешу. Ідеально для HTML-сторінок і API де важлива свіжість.

self.addEventListener('fetch', event => {

event.respondWith(

fetch(event.request)

.then(response => {

if (response.ok) {

const clone = response.clone();

caches.open('dynamic-v2').then(cache => {

cache.put(event.request, clone);

});

}

return response;

})

.catch(() => caches.match(event.request)) // офлайн — з кешу

);

});

Stale While Revalidate

Повертаємо з кешу одразу (швидко!) і паралельно оновлюємо кеш у фоні. Наступний запит отримає вже свіжу версію. Добре для контенту, де невелика затримка оновлення прийнятна.

self.addEventListener('fetch', event => {

event.respondWith(

caches.open('content-v2').then(cache => {

return cache.match(event.request).then(cached => {

const fetchPromise = fetch(event.request).then(response => {

cache.put(event.request, response.clone()); // оновлюємо фоном

return response;

});

return cached || fetchPromise; // повертаємо кеш або чекаємо мережу

});

})

);

});

Cache Only

Тільки кеш, мережа не використовується. Ресурс має бути закешований заздалегідь (наприклад, в install). Використовується для офлайн-fallback сторінок.

self.addEventListener('fetch', event => {

event.respondWith(

caches.match(event.request)

);

});

Як комбінувати стратегії в реальному проєкті

На практиці різні типи ресурсів вимагають різних стратегій. У проєкті Kazki AI використовується такий підхід:

self.addEventListener('fetch', event => {

const url = new URL(event.request.url);

// Не перехоплюємо: POST-запити, API, авторизацію

if (event.request.method !== 'GET') return;

if (url.pathname.startsWith('/api/')) return;

if (url.pathname.startsWith('/login') || url.pathname.startsWith('/oauth2')) return;

// Статика (CSS, JS, шрифти, зображення) — Cache First

if (url.pathname.match(/\.(css|js|woff2|png|jpg|svg)$/)) {

event.respondWith(

caches.match(event.request).then(cached =>

cached || fetch(event.request).then(response => {

caches.open('static-v2').then(c => c.put(event.request, response.clone()));

return response;

})

)

);

return;

}

// HTML-сторінки — Network First

event.respondWith(

fetch(event.request)

.then(response => {

if (response.ok) {

caches.open('pages-v2').then(c =>

c.put(event.request, response.clone())

);

}

return response;

})

.catch(() => caches.match(event.request) || caches.match('/offline.html'))

);

});

Коли Service Worker шкодить — і як не переборщити

Service Worker — потужний інструмент, але він легко перетворюється на джерело проблем якщо використовувати його без обмежень. Ось три ситуації де SW шкодить більше ніж допомагає.

Проблема 1: Кешування HTML-сторінок із стратегією Cache First

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

Правило просте: HTML і API — завжди Network First. Статика (CSS, JS з хешем у назві, шрифти, зображення) — Cache First.

Детальний розбір цієї помилки з кодом — у статті 8 критичних помилок при інтеграції PWA.

Проблема 2: Необмежений розмір кешу

Браузер надає обмежений простір для кешу. Якщо кешувати все підряд — рано чи пізно браузер почне автоматично видаляти старі записи, і ти не будеш контролювати що саме зникне.

Обмежуй розмір кешу вручну. Ось простий підхід — видаляти найстаріші записи коли кеш перевищує ліміт:

const MAX_CACHE_SIZE = 50; // максимум 50 файлів у кеші

async function trimCache(cacheName) {

const cache = await caches.open(cacheName);

const keys = await cache.keys();

if (keys.length > MAX_CACHE_SIZE) {

// видаляємо найстаріші (перші в списку)

await cache.delete(keys[0]);

await trimCache(cacheName); // рекурсивно поки не вкладемось у ліміт

}

}

// Викликаємо після кожного додавання в кеш

self.addEventListener('fetch', event => {

event.respondWith(

fetch(event.request).then(response => {

caches.open('dynamic-v2').then(async cache => {

await cache.put(event.request, response.clone());

await trimCache('dynamic-v2');

});

return response;

})

);

});

Проблема 3: Кешування авторизованих сторінок і персональних даних

Ніколи не кешуй сторінки де є персональні дані користувача, авторизовані API-відповіді або платіжні форми. Якщо закешувати сторінку профілю — є ризик показати дані одного користувача іншому (наприклад, на спільному пристрої).

self.addEventListener('fetch', event => {

const url = new URL(event.request.url);

// Ці маршрути — повністю поза кешуванням

const skipPaths = [

'/api/', '/login', '/logout', '/register',

'/dashboard', '/profile', '/payment', '/admin'

];

if (skipPaths.some(path => url.pathname.startsWith(path))) {

return; // не викликаємо respondWith — браузер іде в мережу напряму

}

// Решта — обробляємо

event.respondWith(/* ... */);

});

Service Workers як вони працюють і чому без них немає офлайн-режиму

Offline fallback і Background Sync

Offline fallback — /offline.html замість динозавра Chrome

Коли користувач офлайн і запитує сторінку якої немає в кеші — браузер за замовчуванням показує стандартну помилку або знаменитого динозавра Chrome. Це погано з точки зору UX — людина не розуміє що відбувається.

Правильне рішення — показувати власну /offline.html сторінку з повідомленням і можливо кнопкою "Спробувати знову".

Спочатку кешуємо offline.html при install:

const STATIC_ASSETS = [

'/',

'/index.html',

'/offline.html', // обов'язково

'/app.css',

'/app.js'

];

self.addEventListener('install', event => {

self.skipWaiting();

event.waitUntil(

caches.open('static-v2').then(cache => cache.addAll(STATIC_ASSETS))

);

});

Потім повертаємо її як fallback коли мережа недоступна:

self.addEventListener('fetch', event => {

// Тільки для навігаційних запитів (сторінки, не ресурси)

if (event.request.mode === 'navigate') {

event.respondWith(

fetch(event.request).catch(() => {

return caches.match('/offline.html');

})

);

return;

}

// Для інших ресурсів — звичайна логіка

});

Так користувач бачить твою branded сторінку з поясненням замість стандартної помилки браузера.

Background Sync — що відбувається з діями офлайн

Background Sync API вирішує важливу проблему: що робити якщо користувач відправив форму або коментар — а в цей момент зникло з'єднання?

Без Background Sync — дані просто втрачаються. З ним — запит ставиться в чергу і автоматично відправляється коли з'єднання відновиться, навіть якщо користувач вже закрив вкладку.

// На сторінці — реєструємо sync тег при спробі відправки

async function submitForm(data) {

try {

await fetch('/api/submit', {

method: 'POST',

body: JSON.stringify(data)

});

} catch (error) {

// Офлайн — зберігаємо дані і реєструємо sync

await saveToIndexedDB('pending-submissions', data);

const registration = await navigator.serviceWorker.ready;

await registration.sync.register('submit-form');

}

}

// У Service Worker — обробляємо коли з'єднання відновилось

self.addEventListener('sync', event => {

if (event.tag === 'submit-form') {

event.waitUntil(

getFromIndexedDB('pending-submissions').then(async items => {

for (const item of items) {

await fetch('/api/submit', {

method: 'POST',

body: JSON.stringify(item)

});

}

await clearIndexedDB('pending-submissions');

})

);

}

});

Підтримка браузерів: Background Sync підтримується в Chrome і Edge. На iOS Safari підтримка з'явилась в Safari 18+ і поки нестабільна. Якщо критична надійність — використовуй як прогресивне покращення поверх звичайного повторного запиту.

Дебаггінг у DevTools — як перевірити що все працює

Service Worker складно дебажити стандартними засобами бо він живе поза сторінкою. Але Chrome DevTools має все необхідне.

Application tab → Service Workers

Відкрий DevTools (F12) → вкладка Application → секція Service Workers.

Тут ти бачиш:

  • Status — активний SW (зелена крапка), waiting (жовта), або зупинений.
  • Source — посилання на файл sw.js. Клік відкриває його в дебаггері.
  • Update on reload — при увімкненні браузер завжди перевіряє нову версію SW при кожному перезавантаженні. Корисно під час розробки.
  • Bypass for network — SW тимчасово вимикається, всі запити йдуть напряму в мережу. Зручно щоб перевірити як сайт виглядає без кешу.
  • skipWaiting — кнопка для примусової активації нового SW що чекає в Waiting стані.

Перевірка кешу

Application → Cache Storage. Тут видно всі кеші з іменами, список закешованих URL і їх розмір. Можна клікнути на будь-який запис і побачити заголовки відповіді.

Симуляція офлайн-режиму

Application → Service Workers → поставити галочку Offline. Або в Network tab → вибрати No throttling → Offline.

Після цього перезавантаж сторінку — ти побачиш що саме показує твій SW в офлайн-режимі. Чи відображається /offline.html? Чи завантажуються кешовані ресурси?

Примусове оновлення SW під час розробки

Щоб не закривати вкладки при кожній зміні sw.js, увімкни Update on reload в Application → Service Workers. Це змушує браузер вважати SW зміненим при кожному перезавантаженні.

Або можна повністю скинути стан: Application → Storage → Clear site data. Це видаляє всі кеші, IndexedDB, cookies і скасовує реєстрацію SW. Корисно коли щось "зависло" і потрібен чистий старт.

Логування в SW

Логи Service Worker не з'являються в звичайній консолі сторінки. Щоб їх побачити — Application → Service Workers → клік inspect поряд з активним SW. Відкриється окремий DevTools вікно з консоллю SW.

// У sw.js — логуємо для дебагу

self.addEventListener('fetch', event => {

console.log('[SW] Перехоплено запит:', event.request.url);

// ...

});

Якщо Service Worker налаштований — логічний наступний крок це push-сповіщення. Service Worker може отримувати їх від сервера навіть коли браузер закритий. Детальний розбір з кодом для iOS — у статті PWA Push-сповіщення на iOS у 2026: що реально працює.

❓ Часті питання (FAQ)

Чи може Service Worker перехоплювати запити інших сайтів?

Ні. Service Worker обмежений своїм origin (протокол + домен + порт) і scope. Він не може перехоплювати запити до інших доменів або модифікувати запити до зовнішніх API — тільки до ресурсів свого домену в межах заданого scope.

Що відбувається якщо в sw.js є синтаксична помилка?

Service Worker не зареєструється. Браузер спробує виконати файл, отримає помилку і відхилить реєстрацію. Вже активний SW продовжить працювати — новий з помилкою його не замінить. Саме тому важливо завжди обробляти .catch() після register() і перевіряти консоль у DevTools під час розробки.

Скільки Service Workers може бути на одному сайті?

Технічно кілька, якщо вони мають різний scope. Наприклад, /sw-shop.js для /shop/* і /sw-blog.js для /blog/*. На практиці один SW в корені з умовною логікою всередині простіший у підтримці.

Чи потрібен Service Worker для звичайного сайту без PWA?

Не обов'язково, але може бути корисним. Навіть без офлайн-режиму SW дає прискорення повторних завантажень через кешування статики і можливість показати офлайн-сторінку замість помилки браузера. Якщо сайт публічний і важлива швидкість — SW варто розглянути навіть без повноцінного PWA.

Чому Service Worker не оновлюється хоча я змінив sw.js?

Найімовірніше новий SW чекає в Waiting стані — стара версія ще активна. Перевір Application → Service Workers в DevTools: якщо бачиш жовту крапку і статус "waiting" — натисни skipWaiting або закрий всі вкладки сайту. У продакшні вирішується через self.skipWaiting() в події install — як показано в розділі про Lifecycle.

Чи впливає Service Worker на SEO?

Може впливати — як позитивно, так і негативно. Позитивно: прискорює завантаження, покращує Core Web Vitals. Негативно: якщо HTML кешується з Cache First — Googlebot може отримувати застарілий контент. Правило: для HTML-сторінок завжди використовуй Network First, щоб пошуковий робот завжди бачив актуальну версію. Детальніше про вплив PWA на SEO — у повному гіді по PWA.

✅ Висновки

Service Worker — це не магія і не складна технологія, якщо розуміти з чого вона складається. Підсумуємо ключове:

  • SW живе в окремому потоці — немає DOM, є Cache API і PushManager. Спілкується зі сторінкою через postMessage.
  • Lifecycle має три стадії — Register → Install → Activate. Пастка Waiting вирішується через skipWaiting() + clients.claim().
  • HTTPS — обов'язкова умова — без нього SW просто не реєструється.
  • Стратегія кешування залежить від типу контенту — статика Cache First, HTML і API Network First, контентні сторінки Stale While Revalidate.
  • Не кешуй все підряд — авторизація, персональні дані і API-відповіді поза кешем. Обмежуй розмір кешу вручну.
  • Offline fallback — завжди готуй власну /offline.html замість стандартної помилки браузера.
  • DevTools — твій головний інструмент для перевірки стану SW, кешу і симуляції офлайн-режиму.

Якщо ти ще вибираєш між PWA та нативним додатком — детальне порівняння з реальними цифрами і кейсом Kazki AI читай у статті PWA Push-сповіщення на iOS у 2026: що реально працює.

📖 Джерела та корисні посилання

Останні статті

Читайте більше цікавих матеріалів

Як перевірити ціну готелю перед бронюванням: технічний гайд

Як перевірити ціну готелю перед бронюванням: технічний гайд

Важливо розуміти одразу: більшість коливань цін на туристичних платформах — це звичайна динамічна зміна попиту, а не обов'язково персоналізація під конкретного користувача. Ціни змінюються залежно від кількості вільних номерів, сезонності та активності інших покупців. Кроки з цього гайду допоможуть...

Reverse Engineering ціноутворення: Як працюють алгоритми Big Data Discrimination

Reverse Engineering ціноутворення: Як працюють алгоритми Big Data Discrimination

Справа Trip.com відкрила публічну дискусію про те, що розробники давно підозрювали: алгоритми туристичних платформ не просто «підбирають кращу ціну» — вони активно профілюють кожного користувача і повертають різну JSON-відповідь залежно від десятків сигналів. У цьому матеріалі ми розберемо...

Антимонопольний удар по Trip.com у 2026: Чому Китай взявся за алгоритми бронювання?

Антимонопольний удар по Trip.com у 2026: Чому Китай взявся за алгоритми бронювання?

Дата публікації: 15 березня 2026Категорія: Аналітика / Big Tech / Регулювання ШІКоли найбільший туристичний агрегатор Азії отримав повістку від регулятора, ринок відреагував миттєво. За лічені години компанія втратила понад $8 мільярдів доларів капіталізації. Але за цією кризою ховається щось...

Service Workers як вони працюють і чому без них немає офлайн-режиму

Service Workers як вони працюють і чому без них немає офлайн-режиму

Уяви Service Worker як проксі між твоїм застосунком і мережею: він перехоплює кожен запит і вирішує — віддати з кешу чи звернутись до сервера. Саме це робить офлайн-режим можливим.Якщо ти вже читав повний гід по PWA, то знаєш що Service Worker — це один з трьох китів Progressive Web App поряд із...

Retention — це новий PageRank: поведінкове SEO та математика популярності TikTok у 2026

Retention — це новий PageRank: поведінкове SEO та математика популярності TikTok у 2026

Тисячі статей про TikTok навчать вас «робити сильний хук». Ця — ні. Тут — механізм когортного тестування, яким алгоритм вирішує долю відео за перші дві години, точна ієрархія сигналів з кількісними даними, і математика save-to-view ratio як аналогу Domain Authority. Аналітично, без банальностей.📚...

PWA Push-сповіщення на iOS у 2026: що реально працює

PWA Push-сповіщення на iOS у 2026: що реально працює

Push-сповіщення для PWA на iOS — одна з найбільш обговорюваних тем серед веб-розробників останніх двох років. Apple довго тримала цю функцію закритою, а коли відкрила — зробила це з обмеженнями, які досі викликають питання на практиці. У цій статті — технічний розбір на...