На протяжении многих лет возможности браузеров постоянно увеличивались в ответ на растущие потребности веб-приложений. И теперь у нас есть множество способов получения одной и той же (или схожей) функциональности. На такую особенность браузеров, как возможность обмена данными между вкладками, редко обращают внимание. Рассмотрим несколько сценариев, в которых она может потребоваться:
- Изменение темы (например, тёмная или светлая тема) приложения распространяется на уже открытые вкладки браузера.
- Получение последнего токена для аутентификации и использование его во всех вкладках браузера.
- Синхронизация состояния приложения во всех вкладках браузера.
На момент написания этой статьи существовало несколько достойных внимания подходов, в соответствии с которыми осуществляется обмен данными между вкладками браузеров. У каждого из этих подходов свои сильные и слабые стороны, поэтому остановимся на них подробнее, чтобы вы могли найти подходящий для вас вариант.
1. «Events» («События
») в локальном хранилище данных
Возможно, вы уже использовали LocalStorage
, который доступен на разных вкладках в рамках одного и того же приложения-источника. Но знаете ли вы, что LocalStorage
поддерживает события? Эту функцию можно использовать для обмена данными между вкладками браузера: хранилище обновляется, после чего событие получат другие вкладки.
Например, в одной вкладке выполняется следующий код JavaScript:
window.localStorage.setItem("loggedIn", "true");
И другие, прослушивающие событие вкладки получат это событие:
window.addEventListener('storage', (event) => {
if (event.storageArea != localStorage) return;
if (event.key === 'loggedIn') {
// Делаем что-нибудь с «event.newValue»
}
});
Но здесь есть несколько ограничений:
- Событие не срабатывает для вкладки, на которой выполняется действие по вводу значений в хранилище.
- Этот подход имеет негативные последствия для большого объёма данных: из-за синхронности выполняемых в
LocalStorage
действий основной поток пользовательского интерфейса может быть заблокирован.
Более подробная информация содержится в разделе «Storage Events» документации MDN.
2. API широковещательного канала
API широковещательного канала позволяет осуществлять обмен данными между вкладками, окнами, фреймами, Iframes и веб-воркерами. Одна вкладка создаёт что-то и опубликовывает это на канале:
const channel = new BroadcastChannel('app-data');
channel.postMessage(data);
А другие вкладки прослушивают канал:
const channel = new BroadcastChannel('app-data');
channel.addEventListener ('message', (event) => {
console.log(event.data);
});
const channel = new BroadcastChannel('app-data');
И таким образом происходит обмен данными между контекстами браузера (окнами, вкладками, фреймами или Iframes). Такой способ обмена данными между вкладками браузера очень удобен. Тем не менее safari
и IE
его не поддерживают. Более подробная информация содержится в разделе «BroadcastChannel» документации MDN.
Подсказка: выкладывайте на Bit (Github) переиспользуемые компоненты для своих проектов. Здесь очень просто размещать, документировать и организовывать независимые компоненты из любого проекта.
Задействуйте этот ресурс для максимально многократного использования кода и совместной работы над независимыми компонентами, а также для создания масштабируемых приложений.
Bit поддерживает Node, TypeScript, React, Vue, Angular и много других инструментов.
3. Сервис-воркеры для отправки сообщений
Здесь у вас может возникнуть вопрос: «Откуда взялись тут сервис-воркеры?». Вообще-то они тоже поддерживают отправку сообщений, поэтому сервис-воркеры можно использовать для обмена данными между вкладками браузера.
Вот как отправляется сообщение с помощью сервис-воркеров:
navigator.serviceWorker.controller.postMessage({
broadcast: data
});
А принимающий воркер на другой вкладке браузера прослушивает это событие:
addEventListener('message', async (event) => {
if ('boadcast' in event.data ) {
const allClients = await clients.matchAll();
for (const client of allClients) {
client.postMessage(event.broadcast);
}
}
});
Это надежный способ передачи сообщений, предоставляющий больше контроля. Но для внедрения сервис-воркеров требуются дополнительные знания об API Service Worker
и чуть больше работы. Так что, если другие подходы не работают, стоит обратить внимание на этот. Более подробная информация содержится в разделе «Service Worker API» документации MDN, а весь пример доступен по этой ссылке.
4. Отправка сообщений между окнами
Подход Window.postMessage()
— один из традиционных способов обмена данными между вкладками браузера. Сообщение отправляется так:
targetWindow.postMessage(message, targetOrigin)
А целевое окно прослушивает события:
рwindow.addEventListener("message", (event) => {
if (event.origin !== "http://localhost:8080")
return;
// Делаем что-нибудь
}, false);
Одно из преимуществ этого подхода перед другими — возможность поддержки обмена данными между разными источниками. Но есть и ограничение: необходима ссылка на другую вкладку браузера. Поэтому этот подход только для вкладок браузера, открытых через window.open()
или document.open()
. Более подробная информация содержится в документации MDN.
Заключение
Надеюсь, статья была для познавательной и рассмотренные в ней подходы будут полезны для ваших веб-приложений. Каждый подход уникален и имеет свои варианты использования.
Кроме этих четырёх подходов, для обмена данными между вкладками браузера и даже между устройствами в режиме реального времени применяются Websockets
(«веб-сокеты») и Server-Sent Events
(«события, посылаемые сервером»). Но для этого понадобится веб-сервер. А вот рассмотренные в статье подходы не зависят от веб-сервера, и их применение позволяет осуществлять обмен данными в браузере без него и делать это быстро.
Спасибо за внимание!
А теперь приступайте к работе над собственным кодом!!! ❤️️
Читайте также:
- Как увеличить производительность CSS-in-JS в 175 раз
- Одномерный клеточный автомат в JavaScript
- Создание пользовательского HTML-элемента без фронтенд-фреймворка
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Dilantha Prasanjith: 4 Ways to Communicate Across Browser Tabs in Realtime