WebSocket добре працює як канал швидкої доставки змін, але саме з’єднання не є гарантією повної історії подій.
Користувач може закрити ноутбук, втратити мережу, перейти між Wi-Fi і мобільним інтернетом або просто мати короткий розрив з’єднання. У цей час сервер продовжує змінювати стан.
Коли клієнт знову під’єднався, статус connected означає лише одне: канал знову доступний. Він не доводить, що між старим і новим з’єднанням нічого не було втрачено.
Розрив з’єднання створює невидиме вікно між подіями
12:00:00 connected12:00:05 disconnected 12:00:08 notification created12:00:12 message read12:00:18 another notification created 12:00:25 connected againУ такому сценарії клієнт може не знати про дві нові нотифікації та про зміну стану повідомлення.
Після повторного підключення нові події вже надходитимуть, але пропущений проміжок сам собою не відновиться.
Подія в реальному часі прискорює інтерфейс, але канонічний стан залишається на сервері
Якщо сервер уже зберігає нотифікації, повідомлення, read_at, кількість непрочитаних або інший достовірний стан, саме він повинен бути основою для відновлення клієнта.
WebSocket-подія потрібна для швидкості. Вона дозволяє не чекати наступного HTTP-запиту, коли зміна відбулася прямо зараз.
Але після невідомого проміжку без зв’язку краще знову запитати сервер, ніж намагатися здогадатися, які саме події могли бути пропущені.
Після повторного підключення потрібна окрема операція звірки
echo.connector.pusher.connection.bind( 'connected', async () => { await refreshUnreadCount(); await refreshRecentNotifications(); },);Конкретний код залежить від WebSocket-клієнта й версії бібліотеки, але принцип стабільний: повторне підключення має запускати звірку.
Це може бути один API-запит із компактним знімком стану або кілька невеликих запитів для тих частин інтерфейсу, які справді залежать від оновлень у реальному часі.
Не обов’язково повторно завантажувати всю сторінку
Звірка не повинна перетворюватися на повне перезавантаження застосунку.
Для нотифікацій часто достатньо отримати:
- актуальну кількість непрочитаних;
- останні кілька нотифікацій;
- ідентифікатор або час останньої відомої зміни;
- за потреби - актуальні стани елементів, які зараз відкриті.
Знімок стану треба поєднувати зі станом клієнта без дублювання
Під час повторного підключення легко отримати одну й ту саму нотифікацію двома шляхами: спочатку через HTTP-запит зі знімком стану, а за мить - через подію в реальному часі.
Тому клієнтський список повинен мати стабільний ідентифікатор і оновлювати елемент за id, а не просто додавати все в кінець масиву.
function upsertNotification( notification,) { const index = notifications.value.findIndex( (item) => item.id === notification.id, ); if (index === -1) { notifications.value.unshift( notification, ); return; }Лічильник краще замінити серверним значенням, а не вгадувати різницю
Після повторного підключення небезпечно робити щось на кшталт "ми, мабуть, пропустили дві події, тому додамо два".
Клієнт не знає, скільки подій було створено, прочитано або видалено під час розриву.
Якщо сервер може повернути unreadCount = 7, клієнт повинен встановити 7, а не намагатися відтворити всі проміжні інкременти.
Для відкритого чату може знадобитися окрема звірка повідомлень
Якщо під час розриву користувач залишався на сторінці конкретного діалогу, після повторного підключення варто перевірити й сам діалог.
Замість повного повторного завантаження історії можна запросити повідомлення після останнього відомого message_id або іншого стабільного курсора.
Це вже не просто "перемалювати UI", а відновити пропущений відрізок історії.
Кожне технічне повторне підключення не повинно запускати шторм HTTP-запитів
Нестабільна мережа може кілька разів поспіль переводити з’єднання між станами disconnected і connected.
Тому звірку варто централізувати, не дублювати в кожному компоненті й за потреби захищати від паралельних повторних запусків.
Один центральний механізм повторного підключення значно безпечніший, ніж десять компонентів, кожен із яких сам вирішує, коли перечитувати сервер.
Початкове завантаження і повторне підключення можуть використовувати той самий шлях синхронізації
async function syncNotificationState() { const state = await api.getNotificationState(); unreadCount.value = state.unreadCount; mergeNotifications( state.notifications, );} onMounted( syncNotificationState,); Повернення у вкладку браузера - ще один хороший момент для звірки
Браузер може призупиняти фонову вкладку, мережеві події можуть приходити із затримкою, а WebSocket може бути перепідключений непомітно для конкретного компонента.
Тому для критичних лічильників і нотифікацій корисно мати ще один дешевий тригер: коли вкладка знову стає видимою, перевірити актуальний стан на сервері.
Це особливо добре працює разом із повторним підключенням, а не замість нього.
Що варто перевірити тестами
1. Після узгодження повторного підключення з'являється пропущене сповіщення.2. Кількість непрочитаних повідомлень замінюється значенням сервера.3. Те саме сповіщення зі знімка та реального часу не дублюється.4. Активний потік отримує повідомлення після останнього відомого курсора.5. Кілька подій повторного підключення не запускають перекриваючі запити на синхронізацію.6. Невдале узгодження можна безпечно повторити.7. Узгодження не очищує новіший стан реального часу.8. Повернення до видимої вкладки браузера може оновити застарілі лічильники.9. Початкове завантаження та повторне підключення використовують той самий канонічний шлях синхронізації.10. Події WebSocket продовжують оновлювати інтерфейс користувача після завершення узгодження.Повторне підключення відновлює канал, але звірка відновлює достовірний стан
Повторне WebSocket-підключення потрібне, щоб клієнт знову почав отримувати нові події.
Але для правильного стану інтерфейсу цього недостатньо. Клієнт повинен перевірити, що сталося під час розриву, через канонічний серверний стан.
Оновлення в реальному часі відповідають за швидкість реакції. Серверна звірка відповідає за відновлення достовірного стану після невідомого проміжку без зв’язку.
Після повторного підключення я довіряю стану не тому, що з’єднання знову зелене, а тому, що клієнт повторно звірився із сервером.



