Подтвердить что ты не робот

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

// 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(). Я протестировал, чтобы сделать очень длинный цикл for(), и он все еще ждал завершения цикла до закрытия. Если пользователь убивает вкладку только в промежутке между ними, браузер не будет иметь достаточно времени для сохранения сообщения на диск, поэтому такой подход кажется мне безопасным способом отправки сообщений без каких-либо следов. Комментарии приветствуются.

Ответ 2

Для тех, кто ищет решение, не основанное на jQuery, это простая версия JavaScript, предоставленная Томасом М:

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);
    }
}

Ответ 3

Для этой цели существует современный 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, но вы можете найти polyfill, который использует localStorage.

Ответ 4

Оформить заказ AcrossTabs - Простая связь между вкладками браузера кросс-начала.. Он использует сочетание postMessage и sessionStorage API для сделать общение намного проще и надежнее.


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

  • LocalStorage

    Профи:

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

    против

  • Cookies

    Плюсы:

    • По сравнению с другими, ничего AFAIK.

    Минусы:

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

      Обычно допустимы следующие действия:

      • 300 файлов cookie
      • 4096 байт для каждого файла cookie
      • 20 файлов cookie для каждого домена
      • 81920 байт для каждого домена (задано 20 файлов cookie максимального размера 4096 = 81920 байт.)
  • sessionStorage

    Плюсы:

    • Он похож на localStorage.
    • Изменения доступны только для каждого окна (или вкладки в браузерах, таких как Chrome и Firefox). Сделанные изменения сохраняются и доступны для текущей страницы, а также для будущих посещений сайта в том же окне. Когда окно закрыто, хранилище удаляется.

    Минусы:

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

    Плюсы:

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

    Минусы:

    • Необходимо открыть окно из текущего окна, а затем связаться только до тех пор, пока вы не открываете окна.
    • Проблемы безопасности. Отправка строк через postMessage заключается в том, что вы будете получать другие события postMessage, опубликованные другими плагинами JavaScript, поэтому обязательно выполните targetOrigin и проверку работоспособности передаваемых данных на прослушиватель сообщений.
  • Комбинация postMessage + sessionStorage

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

Я написал для этого библиотеку JavaScript, названную AcrossTabs, которая использует API PostMessage для связи между перекрестным происхождением вкладки/окна и sessionStorage, чтобы сохранить открытые идентификаторы вкладок/окон, пока они живут.

Ответ 5

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

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

Ответ 6

Там крошечный компонент с открытым исходным кодом для синхронизации/обмена между вкладками/окнами одного и того же происхождения (отказ от ответственности - я один из участников!), основанный на 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

P.S. Я взял на себя смелость рекомендовать его здесь, так как большинство компонентов "lock/mutex/sync" терпят неудачу при подключении к сети, когда события происходят почти одновременно.

Ответ 7

Я написал статью об этом в своем блоге: 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

Существуют и другие удобные методы для обработки других сценариев.