Спілкування скриптів з різних вкладок браузера

Мені захотілося налагодити спілкування скриптів з різних вкладок браузера. Майбутній API SharedWorker дозволяє передавати дані між різними iframe і навіть вкладками або вікнами. У Chrome він працює давно, Firefox, Firefox — недавно, а в IE і Safari його не бачити. Але існує кросбраузерна альтернатива, про яку мало хто знає. Давайте розбиратися.

Уявіть, що на одній вкладці людина залогінився, потім відкрив іншу, і там разлогинился. На першій він начебто залягання, але коли він зробить там що-небудь, йому видадуть помилку. Добре було б хоча б показати йому діалог про те, що він разлогинился і йому треба увійти ще раз.

Можна було б використовувати API WebSocket, але це занадто складно. Я почав шукати інші рішення. Перше — зберегти куки і localStorage, і перевіряти їх періодично. Але це навантажувала б процесор досить марною завданням — адже виходу могло і не відбутися взагалі. Мене більше влаштували б варіанти з long-polling (довгі запити), Server-Sent Events або WebSockets. Дивно, але в результаті виявилося, що відповідь лежав в області localStorage!

Чи знаєте ви, що localStorage запускають події? Точніше, подія виникає, коли щось додається, змінюється або видаляється зі сховища. Це означає, що коли ви торкаєтеся localStorage в будь-якій вкладці, всі інші можуть дізнатися про це. Досить прослуховувати події в об'єкті window.

window.addEventListener. ('storage', function (event) {
console.log(event.key, event.newValue);
});


Об'єкт event є наступні властивості:

key — ключ, який чіпали в localStorage
newValue — нове призначене йому значення
oldValue — значення перед зміною
url — URL сторінки, на якій сталося зміна

Тому можна налагодити спілкування між вкладками, просто задаючи значення в localStorage. Уявіть наступний приклад (псевдокод):

var loggedOn;

// TODO: коли користувач змінюється або виходить
logonChanged();

window.addEventListener. ('storage', updateLogon);
window.addEventListener. ('focus', checkLogon);

function getUsernameOrNull () {
// TODO: повернення, коли користувач входить
}

function logonChanged () {
var uname = getUsernameOrNull();
loggedOn = uname;
localStorage.setItem('logged on', uname);
}

function updateLogon (event) {
if (event.key === 'logged on') {
loggedOn = event.newValue;
}
}

function checkLogon () {
var uname = getUsernameOrNull();
if (uname !== loggedOn) {
location.reload();
}
}


Коли користувач виходить на одній з вкладок, і переходить на іншу, сторінка перезавантажується і серверна логіка перенаправляє його кудись. При цьому перевірка відбувається лише якщо користувач вибрав цю вкладку. Якщо раптом він вийшов і зайшов на одній з вкладок, немає потреби разлогинивать його на всіх інших.

Це повинно працювати і в іншу сторону — якщо користувач залогінився на одній вкладці, а на іншій він був разлогинен, то при переході на другу вкладку сторінка перезавантажиться і він там теж буде залягання. Радість.

API простіше

localStorage API — один з найбільш простих інтерфейсів. Проте і у нього є особливість — наприклад, Safari і QuotaExceededError, немає підтримки JSON і старих браузерів.

Для цього я зробив модуль, який надає локальне сховище з спрощеним API, що позбавляє вас від зазначених особливостей, що працює з пам'яттю, якщо раптом підтримки localStorage немає, і дозволяє простіше працювати з подіями. Можна реєструвати і видаляти слухачів цих подій для заданих ключів.

Ось схема роботи з local-storage.

ls(key, value?) отримує або встановлює значення ключа
ls.get(key) отримує значення ключа
ls.set(key, value) задає значення
ls.remove(key) видаляє ключ
ls.on(key, fn(value, old, url)) слухає зміни в інших вкладках, запускає fn
ls.off(key, fn) видаляє слухача, який був зареєстрований через ls.on

Варто згадати, що local-storage реєструє один обробник подій і відстежує всі ключі, за якими ви спостерігаєте, замість реєстрації безлічі подій.

Напевно можна придумати й інші випадки, коли можливо використовувати спілкування між вкладками. Поки SharedWorker не отримав належного поширення, а підхід WebSockets ненадійний, якщо ваш додаток орієнтується в першу чергу на роботу оффлайн.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.