Связь между вкладками или окнами



Я искал способ, как общаться между несколькими вкладками или окнами в браузере (на том же домене, а не CORS), не оставляя следов. Было несколько решений:




  1. используя объект window

  2. postMessage

  3. cookies

  4. localStorage


первое, вероятно, худшее решение - вам нужно открыть окно из вашего текущего окно, а затем вы можете общаться только до тех пор, пока вы держите окна открытыми. Если вы перезагрузите страницу в любом из окон, вы, скорее всего, потеряли связь.



второй подход, использующий postMessage, вероятно, обеспечивает связь между источниками, но страдает той же проблемой, что и первый подход. Вам нужно поддерживать объект окна.



Третий способ, используя куки, хранить некоторые данные в браузере, который может эффективно выглядеть как отправка сообщения во все окна на тот же домен, но проблема в том, что вы никогда не можете знать, все ли вкладки читают "сообщение" уже или нет перед очисткой. Вы должны реализовать какой-то тайм-аут, чтобы периодически читать куки. Кроме того, вы ограничены максимальной длиной файла cookie, которая составляет 4 КБ.



четвертое решение, используя localStorage, казалось бы, преодолеть ограничения куки, и это может быть даже прослушивание с помощью событий. Как его использовать описано в принятом ответе.



изменить 2018: принятый ответ все еще работает, но есть более новое решение для современных браузеров, чтобы использовать BroadcastChannel. См. другой ответ для простого примера, описывающего, как легко передавать сообщение между вкладками с помощью BroadcastChannel.

826   8  

8 ответов:

Edit 2018: вы можете лучше использовать BroadcastChannel для этой цели, см. другие ответы ниже. Тем не менее, если вы все еще предпочитаете использовать localstorage для связи между вкладками, сделайте это следующим образом:

чтобы получить уведомление, когда вкладка отправляет сообщение на другие вкладки, вам просто нужно привязать событие "хранение". Во всех вкладках, сделайте следующее:

$(window).on('storage', message_receive);

функции message_receive будет вызываться каждый раз, когда вы устанавливаете любое значение из localStorage в любой другой вкладке. Событие прослушиватель также содержит данные, недавно установленные в localStorage, поэтому вам даже не нужно анализировать сам объект localStorage. Это очень удобно, потому что вы можете сбросить значение сразу после его установки, чтобы эффективно очистить любые следы. Вот функции для обмена сообщениями:

// use local storage for messaging. Set message in local storage and clear it right away
// This is a safe way how to communicate with other tabs while not leaving any traces
//
function message_broadcast(message)
{
    localStorage.setItem('message',JSON.stringify(message));
    localStorage.removeItem('message');
}


// receive message
//
function message_receive(ev)
{
    if (ev.originalEvent.key!='message') return; // ignore other keys
    var message=JSON.parse(ev.originalEvent.newValue);
    if (!message) return; // ignore empty msg or msg reset

    // here you act on messages.
    // you can send objects like { 'command': 'doit', 'data': 'abcd' }
    if (message.command == 'doit') alert(message.data);

    // etc.
}

Итак, теперь, когда ваши вкладки привязываются к событию onstorage, и у вас есть эти две функции, вы можете просто транслировать сообщение на другие вкладки, вызывающие, например пример:

message_broadcast({'command':'reset'})

помните, что отправка одного и того же сообщения дважды будет распространяться только один раз, поэтому, если вам нужно повторить сообщения, добавьте к ним уникальный идентификатор, например

message_broadcast({'command':'reset', 'uid': (new Date).getTime()+Math.random()})

также помните, что текущая вкладка, которая транслирует сообщение, фактически не получает его, только другие вкладки или окна в том же домене.

вы можете спросить, что произойдет, если пользователь загрузит другую веб-страницу или закроет свою вкладку сразу после вызова setItem () перед removeItem (). Ну, от моего собственного тестирования браузер ставит выгрузку на удержание, пока вся функция message_broadcast() закончена. Я проверил, чтобы положить туда какой-то очень длинный цикл (), и он все еще ждал завершения цикла перед закрытием. Если пользователь убивает вкладку только между ними, то у браузера не будет достаточно времени, чтобы сохранить сообщение на диск, поэтому этот подход кажется мне безопасным способом отправки сообщений без каких-либо следов. Комментарии приветствуются.

существует современный API, предназначенный для этой цели - Трансляция Телеканала

Это так же просто, как:

var bc = new BroadcastChannel('test_channel');

bc.postMessage('This is a test message.'); /* send */

bc.onmessage = function (ev) { console.log(ev); } /* receive */

нет необходимости, чтобы сообщение было просто DOMString, любой объект может быть отправлен.

вероятно, помимо чистоты API, это главное преимущество этого API - отсутствие объектной стрингификации.

в настоящее время поддерживает только в Chrome и Firefox, но вы можете найти полифилл что использует хранилище localStorage.

для тех, кто ищет решение, не основанное на jQuery, это простая версия JavaScript решения, предоставленного Thomas M:

window.addEventListener("storage", message_receive);

function message_broadcast(message) {
    localStorage.setItem('message',JSON.stringify(message));
}

function message_receive(ev) {
    if (ev.key == 'message') {
        var message=JSON.parse(ev.newValue);
    }
}

оформить заказ AcrossTabs -легкая связь между вкладками браузера cross-origin. он использует комбинацию postMessage и sessionStorage API, чтобы сделать общение намного проще и надежнее.


существуют разные подходы, и каждый из них имеет свои преимущества и недостатки. Давайте обсудим каждый:

  1. LocalStorage

    плюсы:

    1. веб-хранилище можно рассматривать упрощенно как улучшение файлов cookie, обеспечивая гораздо большую емкость хранилища. Если вы посмотрите на исходный код Mozilla, мы видим, что 5120KB (5МБ что составляет 2,5 миллиона символов на Chrome) - это размер хранилища по умолчанию для всего домена. Это дает вам значительно больше места для работы, чем типичный 4KB cookie.
    2. данные не отправляются обратно на сервер для каждого HTTP-запроса (HTML, изображения, JavaScript, CSS и т. д.) - уменьшение объема трафика между клиентом и сервером.
    3. данные, хранящиеся в localStorage, сохраняются до явного удаления. Внесенные изменения сохраняются и доступны для всех текущих и будущих посещений сайта.

    минусы:

    1. он работает на политика того же происхождения. Таким образом, сохраненные данные будут доступны только в том же источнике.
  2. Cookies

    плюсы:

    1. по сравнению с другими, нет ничего AFAIK.

    плюсы:

    1. ограничение 4K предназначено для всего файла cookie, включая имя, значение, дату истечения срока действия и т. д. Чтобы поддерживать большинство браузеров, сохраните имя менее 4000 байт, а общий размер файла cookie менее 4093 байт.
    2. данные отправляются обратно на сервер для каждого HTTP-запроса (HTML, изображения, JavaScript, CSS и т. д.) - увеличение объема трафика между клиентом и сервером.

      как правило, допускаются следующие действия:

      • 300 cookies в общей сумме
      • 4096 байт за печенье
      • 20 cookies per домен
      • 81920 байт на домен (учитывая 20 файлов cookie максимального размера 4096 = 81920 байт.)
  3. sessionStorage

    плюсы:

    1. это похоже на localStorage.
    2. изменения доступны только для каждого окна (или вкладки в браузерах, таких как Chrome и Firefox). Внесенные изменения сохраняются и доступны для текущей страницы, а также будущие посещения сайта в этом же окне. После закрытия окна хранилище удаляется

    плюсы:

    1. данные доступны только внутри окна / вкладки, в которой они были установлены.
    2. данные не являются постоянными, т. е. они будут потеряны после закрытия окна/вкладки.
    3. как localStorage, tt работает на политика того же происхождения. Таким образом, сохраненные данные будут доступны только на том же самом происхождение.
  4. PostMessage

    плюсы:

    1. безопасно позволяет cross-origin общение.
    2. в качестве точки данных реализация WebKit (используемая Safari и Chrome) в настоящее время не применяет никаких ограничений (кроме тех, которые налагаются из-за нехватки памяти).

    плюсы:

    1. нужно открыть окно из текущего окна, а затем может общаться только пока вы держите окна открытыми.
    2. проблемы безопасности - отправка строк через postMessage заключается в том, что вы будете подбирать другие события postMessage, опубликованные другими плагинами JavaScript, поэтому обязательно реализуйте targetOrigin и проверить правильность данных на слушателя сообщения.
  5. сочетание PostMessage + SessionStorage

    использование postMessage для связи между несколькими вкладками и в то же время использование sessionStorage во всех вновь открытых вкладках/окнах для сохранения передаваемых данных. Данные будут сохраняться до тех пор, пока вкладки/окна остаются открытыми. Таким образом, даже если вкладка/окно открывателя будет закрыта, открытые вкладки/окна будут иметь все данные даже после обновления.

Я написал библиотека JavaScript для этого, с именем AcrossTabs который использует API postMessage для связи между вкладками/окнами cross-origin и sessionStorage для сохранения открытых вкладок/идентификаторов windows до тех пор, пока они живут.

еще один метод, который люди должны рассмотреть с помощью общих работников. Я знаю, что это передовая концепция, но вы можете создать ретрансляцию на общем рабочем столе, который намного быстрее, чем localstorage, и не требует отношений между родительским/дочерним окном, если вы находитесь в одном и том же источнике.

смотрите мой ответ здесь для некоторого обсуждения я сделал об этом.

есть крошечный компонент с открытым исходным кодом для синхронизации / связи между вкладками / окнами одного и того же происхождения (отказ от ответственности - я один из участников!) основанный вокруг localStorage.

TabUtils.BroadcastMessageToAllTabs("eventName", eventDataString);

TabUtils.OnBroadcastMessage("eventName", function (eventDataString) {
    DoSomething();
});

TabUtils.CallOnce("lockname", function () {
    alert("I run only once across multiple tabs");
});

https://github.com/jitbit/TabUtils

Я создал модуль, который работает наравне с официальным Broadcastchannel но имеет резервные копии на основе localstorage, indexeddb и unix-сокетов. Это гарантирует, что он всегда работает даже с Webworkers или NodeJS. Смотрите pubkey: BroadcastChannel

Я написал статью об этом в своем блоге: http://www.ebenmonney.com/blog/how-to-implement-remember-me-functionality-using-token-based-authentication-and-localstorage-in-a-web-application .

используя библиотеку, которую я создал storageManager вы можете добиться этого следующим образом:

storageManager.savePermanentData('data', 'key'): //saves permanent data
storageManager.saveSyncedSessionData('data', 'key'); //saves session data to all opened tabs
storageManager.saveSessionData('data', 'key'); //saves session data to current tab only
storageManager.getData('key'); //retrieves data

есть и другие удобные способы, а также для обработки других сценариев, а также

Comments

    Ничего не найдено.