← Назад к вопросам

Как из одной вкладки приложения передать информацию в другую?

1.8 Middle🔥 161 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Передача данных между вкладками браузера

Способы коммуникации между вкладками

В браузере существует несколько способов обмена информацией между открытыми вкладками одного сайта:

1. localStorage (Простой способ)

localStorage — это хранилище данных, общее для всех вкладок одного домена:

// Вкладка 1: отправляем данные
localStorage.setItem('userInfo', JSON.stringify({
  id: 123,
  name: 'John Doe'
}));

// Вкладка 2: получаем данные
const userInfo = JSON.parse(localStorage.getItem('userInfo'));
console.log(userInfo); // { id: 123, name: 'John Doe' }

Проблема: localStorage синхронное хранилище, нет события при изменении в другой вкладке (только в старых браузерах есть storage event).

2. Storage Event (Рекомендуемый способ)

Storage Event — это событие, которое срабатывает в других вкладках при изменении localStorage:

// Вкладка 1: отправляем данные
function sendDataToOtherTabs(key, value) {
  localStorage.setItem(key, JSON.stringify(value));
}

sendDataToOtherTabs('notification', {
  message: 'Пользователь вошел в систему',
  timestamp: Date.now()
});

// Вкладка 2: слушаем изменения
window.addEventListener('storage', (e) => {
  if (e.key === 'notification') {
    const data = JSON.parse(e.newValue);
    console.log('Получено:', data.message);
  }
});

Важно: Storage Event срабатывает только в других вкладках, не в той, которая изменила localStorage.

3. Broadcast Channel API (Современный способ)

BroadcastChannel — это API для коммуникации между вкладками одного домена:

// Создаём канал коммуникации
const channel = new BroadcastChannel('user_updates');

// Вкладка 1: отправляем сообщение
function loginUser(user) {
  // Логика входа...
  
  // Отправляем информацию в другие вкладки
  channel.postMessage({
    type: 'USER_LOGIN',
    payload: {
      userId: user.id,
      userName: user.name,
      loginTime: new Date()
    }
  });
}

// Вкладка 2: слушаем сообщения
channel.addEventListener('message', (event) => {
  if (event.data.type === 'USER_LOGIN') {
    console.log('Пользователь вошел:', event.data.payload.userName);
    updateUIWithUserInfo(event.data.payload);
  }
});

// Когда вкладка закрывается
window.addEventListener('beforeunload', () => {
  channel.close();
});

Преимущества:

  • Простой API для обмена сообщениями
  • Работает только в других вкладках
  • Поддерживается всеми современными браузерами

4. SharedWorker (Для сложных сценариев)

SharedWorker — это worker, который может быть общим для нескольких вкладок:

// shared-worker.js (отдельный файл)
const connections = [];

self.addEventListener('connect', (e) => {
  const port = e.ports[0];
  connections.push(port);
  
  port.addEventListener('message', (event) => {
    // Рассылаем сообщение всем подключенным вкладкам
    connections.forEach(p => {
      if (p !== port) {
        p.postMessage(event.data);
      }
    });
  });
  
  port.start();
});

// В каждой вкладке
const worker = new SharedWorker('shared-worker.js');

// Вкладка 1: отправляем данные
worker.port.postMessage({
  type: 'UPDATE_THEME',
  theme: 'dark'
});

// Вкладка 2: слушаем
worker.port.addEventListener('message', (event) => {
  if (event.data.type === 'UPDATE_THEME') {
    applyTheme(event.data.theme);
  }
});

worker.port.start();

5. Service Worker с Message Channel

Для более надежной коммуникации можно использовать Service Worker:

// Вкладка 1: отправляем через Service Worker
navigator.serviceWorker.ready.then((registration) => {
  registration.active.postMessage({
    type: 'BROADCAST',
    data: {
      event: 'SYNC_DATA',
      payload: { /* данные */ }
    }
  });
});

// service-worker.js
self.addEventListener('message', (event) => {
  if (event.data.type === 'BROADCAST') {
    // Транслируем во все clients (все вкладки)
    self.clients.matchAll().then(clients => {
      clients.forEach(client => {
        client.postMessage(event.data);
      });
    });
  }
});

// Вкладка 2: слушаем
navigator.serviceWorker.addEventListener('message', (event) => {
  if (event.data.type === 'BROADCAST') {
    console.log('Получено:', event.data.data);
  }
});

6. IndexedDB (Для большого объема данных)

Если нужно передать много данных, используй IndexedDB с Storage Event:

// Вкладка 1: сохраняем большой объем данных
async function saveLargeData(data) {
  const db = await openIndexedDB();
  const tx = db.transaction('cache', 'readwrite');
  await tx.store.put({ id: 'main_data', value: data });
  
  // Уведомляем другие вкладки
  localStorage.setItem('db_update', Date.now().toString());
}

// Вкладка 2: получаем данные
window.addEventListener('storage', async (e) => {
  if (e.key === 'db_update') {
    const db = await openIndexedDB();
    const tx = db.transaction('cache', 'readonly');
    const data = await tx.store.get('main_data');
    console.log('Получены данные из IndexedDB:', data.value);
  }
});

Сравнение способов

СпособПростотаПроизводительностьРазмер данныхПоддержка
localStorage + Storage EventВысокаяХорошоОграничен (5-10 МБ)Везде
BroadcastChannelВысокаяОтличноХорошийСовременные браузеры
SharedWorkerСредняяОтличноХорошийНе все браузеры
Service WorkerСложнаяОтличноХорошийСовременные браузеры
IndexedDBСредняяОтличноОчень большойВезде

Практический пример: Синхронизация темы

class ThemeSync {
  constructor() {
    this.channel = new BroadcastChannel('theme_channel');
    this.init();
  }
  
  init() {
    // Слушаем изменения темы из других вкладок
    this.channel.addEventListener('message', (e) => {
      if (e.data.type === 'THEME_CHANGED') {
        this.applyTheme(e.data.theme);
      }
    });
  }
  
  setTheme(theme) {
    // Сохраняем локально
    localStorage.setItem('theme', theme);
    
    // Применяем
    this.applyTheme(theme);
    
    // Уведомляем другие вкладки
    this.channel.postMessage({
      type: 'THEME_CHANGED',
      theme: theme
    });
  }
  
  applyTheme(theme) {
    document.documentElement.setAttribute('data-theme', theme);
  }
}

const themeSync = new ThemeSync();
themeSync.setTheme('dark');

Итоги

Рекомендуемый выбор:

  • Просто и легко: localStorage + Storage Event
  • Современно и надежно: BroadcastChannel API
  • Большие объемы: IndexedDB + Storage Event
  • Сложная синхронизация: Service Worker + Message Channel

Для большинства случаев BroadcastChannel — это лучший выбор: простой API, хорошая производительность и полная поддержка современных браузеров.