Работа с localStorage достаточна проста, данные хранятся в виде строк:
// Сохранение значения
localStorage.setItem(key, value)
localStorage[key] = value
// Получение значения
localStorage.getItem(key)
localStorage[key]
// Удаление значения
localStorage.removeItem(key)
delete localStorage[key]
// Очистка всего хранилища
localStorage.clear()
Самое интересное здесь событие window storage, которое генерируется при изменении значения элемента localStorage.
window.addEventListener('storage', function(events) {
console.dir(events);
});
StorageEvent вызывается каждый раз, когда произошло изменение в localStorage. Это не работает на странице, которая вносит изменения, но срабатывает на открытых страницах домена в броузере. То есть, данное событие оповещает открытые вкладки одного сайта о произошедшем событии.
В целях изучения данной технологии мной был написан небольшой скрипт для демонстрации работы localStorage с вкладками броузера.
Попутно, для удобства, был добавлен функционал позволяющий расширить localStorage, хранить и извлекать из localStorage типы значений Null, Date, Number, Boolean, Function
Использование:
<script src="storage.js"></script>
Варианты установки значений
_storage('name', 'Ivan');
_storage('test', [1, 2, 3]);
_storage('obj', {van: 1, two: 2});
_storage('mydate', new Date);
_storage('fn', function(){
alert('Hi');
};
var storage = _storage();
storage.set('name', 'Ivan');
storage
.set('test', [1, 2, 3])
.set('mydate', new Date)
.set('obj', {van: 1, two: 2});
Варианты получения значений:
console.log(_storage('name')); // Ivan
console.dir(_storage('test')); // [1, 2, 3] type: [object Array]
console.dir(_storage('mydate')); // type: [object Date];
console.dir(_storage('fn')); // type: [object Function]
console.dir(_storage('obj')); // type: [object Object]
var storage = _storage();
alert(storage.get('name'));
_storage('fn')(); // call function
storage.get('fn')(); // call function
Подписаться на изменение значения:
_storage().subscribe('message', function (value, e) {
// value - new value
// e - event object
});
var storage = _storage();
storage.subscribe('message', function (value, e) {
// value - new value
// e - event object
}).subscribe('fn', function (fn, e) {
fn(); //call function
// fn - new value
// e - event object
});
Проще один раз увидеть:
git clone https://github.com/Poznakomlus/localstorage.git
cd localstorage
npm install
node run.js
При этом у нас запустится сервер по адресу http://127.0.0.1:7777 и в браузере откроются две страницы этого сервера (Sender, Recipient) для подробной демонстрации описанного. Вы сможете передавать данные из страницы Sender странице Recipient.
Пользуйтесь на здоровье.
Комментарии (39)
vintage
14.12.2016 15:05Зачем вы функции-то сериализуете?
А ещё вы можете записать строку ":b:hello", а прочитать false.
RubaXa
14.12.2016 22:02+2А чего вы минусует vintage, он всё правильно задал вопрос, стерилизовать функции глупость, любая внешняя зависимость из родительского scope и при десереиализации будет вызрыв.
Единственно корректный способ стерилизации/десерилазиции из коробки, это
JSON.parse
иJSON.stringinfy
.
Так что я бы не советовал использовать эту поделку, а взять нормальный store.js
vlasenkofedor
14.12.2016 22:35-1стерилизовать функции глупость
стерилизовать это как? Не выдумывайте новые понятия.
Смотрите внимательно код. Для функций используется toString
не советовал использовать эту поделку
Простите, но я нечего не подделывал и не собиралсяRubaXa
14.12.2016 22:40+2стерилизовать это как? Не выдумывайте новые понятия.
Мило :] На это и закончим.
Carduelis
15.12.2016 13:51-1Вы бы поделились с сообществом, как вы функции стерилизуете. А то гугл мне все про собак да кошек выдает. Не думаю, что большинство знает о чем вы.
RubaXa
15.12.2016 13:56Ну не надо ерничать, да ещё и сообщество принижать, всем и так понятно о чем там написано, несмотря на автокоррекцию.
RubaXa
14.12.2016 17:48+3Доступ и работа с
localStorage
безtry catch
, а-та-тат, исправьте, пока кто-нибудь не поранился.
StorageEvent вызывается каждый раз, когда произошло изменение в localStorage.
Неа, не всегда, в Chrome есть баг, при измененном
document.domain
события не будет, надо детектить и делать хоть какой-то fallback черезsetTimeout
.vlasenkofedor
14.12.2016 22:25работа с localStorage без try catch, а-та-тат, исправьте
Покажите где в данном примере не хватает по вашему убеждению try catchRubaXa
14.12.2016 22:39Везде, о чем я и написал, но мне не сложно, вот:
- https://github.com/Poznakomlus/localstorage/blob/main/storage.js#L15 — это конечно тоже ошибка, если на проекте есть глобальный объект
Storage
, то ваш либа взорвется, корректноwindow.Storage
- https://github.com/Poznakomlus/localstorage/blob/main/storage.js#L99
- https://github.com/Poznakomlus/localstorage/blob/main/storage.js#L151
- https://github.com/Poznakomlus/localstorage/blob/main/storage.js#L161
- https://github.com/Poznakomlus/localstorage/blob/main/storage.js#L170
vintage
14.12.2016 23:03Установка значения может упереться в отсутствие памяти, но то может произойти с чтением значения?
RubaXa
14.12.2016 23:22localStorage
может быть банально битым, или определенные политики безопасности полностью запрещают к нему доступ, но там эксепшен будет уже на стадииwindow.localStorage
.
vlasenkofedor
15.12.2016 04:48Простите, но мы по разному думаем. В вашем предложении я должен обернуть в try catch нативные методы по работе с Loalstorage
В документации по ним нет упоминаний, что выбрасываются исключения.
Далее, вовсе не понятно, что-же я в таком случае должен вернуть и как отрабатывать должен остальной участок кода.
Я говорю о том, что в приложении (не в storage.js) стоит раз проверять на доступность данной (localstorage) функции и затем использовать функции _storage.
А не оборачивать логику ненужными проверками. Логику не только storage, но и логику приложения. И еще раз хочу отметить, что это пример, это не библиотека (нет тестов, документации и т.д.) Пример демонстрации работы. Пощупать, увидеть глазами как это работает.imgen
15.12.2016 10:51+1нужно смотреть в сюда
vlasenkofedor
15.12.2016 12:03imgen, спасибо, не знал о таком поведении браузеров
Технология доступна и в то-же время исключение.
vlasenkofedor
15.12.2016 13:03Тогда перед использованием
function storageEnable() { var state = false; try { window.localStorage.setItem('test', 1); state = window.localStorage.getItem('test') == 1; window.localStorage.removeItem('test'); } catch (err) { console.log(err); } return state; } console.log(storageEnable()); // утка :-)
- https://github.com/Poznakomlus/localstorage/blob/main/storage.js#L15 — это конечно тоже ошибка, если на проекте есть глобальный объект
kapuletti
14.12.2016 18:42+1Данные хранятся до того пока пользователь не очистит их принудительно (историю броузера) или с помощью JavaScript.
Или до тех пор, пока браузер сам не решит удалить данные, как например это делает Safari в iOS при недостатке свободного места.
madMxg
14.12.2016 21:25+1Есть же отличная библиотека от Mozilla localForage
Event'ы навешать можно вот этим localForage-observable
Sombressoul
14.12.2016 22:45+1Что касается расшаривания событий, данных и задач между вкладками (в обход сервера), то я пару лет назад писал на эту тему.
PaulMaly
Всегда бесило, что событие не приходит для текущей вкладки. До сих пор не понимаю зачем такое ограничение.
Frozik
Текущая вкладка и так знает, что и когда меняет, а вот для атомарности нужно отделять свои и чужие события.
vintage
Что такое "атомарность"?
Frozik
Есть достаточно неплохая статья.
vintage
Можно вкратце по-русски?
Frozik
Проблему можно описать следующим способом — в хранилище у нас есть некий ключ, который мы увеличиваем на 1 каждый раз, когда вызываем некую функцию. Сложность состоит в том, что для того, чтобы увеличить значение нам сначала надо прочитать старое. У нас получается 2 операции — чтение и запись нового значения. Исходя из этого могут возникнуть проблемы, что 2 конкурирующие вкладки могут перезаписать значения друг друга. Конечно в браузерах есть специальные механизмы защиты от этого поведения (storage mutex), но операция остается не атомарной, то есть 2 операции чтения и записи не выполняются как одна.
vintage
Так, и при чём тут события в той же вкладке?
Frozik
Чтобы мы могли гарантированно отличить наши и чужие вмешательства в хранилище. Иначе мы этого сделать не сможем (конечно в StorageEvent можно добавить параметр для определения того, что это мы недавно сделали изменения, а не в другой вкладке, но это выглядит как костыль). Так как мне не приходилось сталкиваться с такой проблемой на практике, и я не учил детально матчасть, но могу указать стартовую точку, с которой это можно сделать.
vintage
А какая разница наше это вмешательство или не наше? Оно в любом случае будет неатомарное.
Frozik
Прошу прощения, я некорректно высказался выше про атомарность. Я имел в виду не как её реализовать на событиях, а как бороться с проблемами. Мы стандартными средствами не сможем добиться атомарности (хотя тут человек говорит, что он сделать блокировку — первая статья), но мы сможем устранить проблемы.
PaulMaly
Зачем мне гарантированно отличать из какой вкладки пришли изменения, если меня всего лишь интересует какое значение сейчас в сторе и каким оно было до этого. Все эти данные есть в ивенте. Кто конкретно последним перезаписал значение меня не интересует, только уведомление об итоговом результате.
Опять же, если надо наверняка быть уверенным что изменения пришли от текущего или же другого окна, то скорее всего можно как-то сравнить текущий window со значением из ивента. Однако я не уверен, никогда так не делал, ибо все равно для текущей вкладки событие не работает. В любом случае, такое можно было бы реализовать и не понятно, почему это не сделано.
RubaXa
Именно, никто не мешал добавить
event.source
, как уpostMessage
.PaulMaly
Собственно у меня такая же ассоциация возникла. Иными словами тут проблемы вообще нет и ограничение искусственное.
Frozik
Тогда бы еще пришлось решать проблему ограничения доступа к другому объекту, а также серьезно подумать про синхронизацию.
RubaXa
К какому другому? Какую синхронизацию? Почему этих проблем нет у
postMessage
?PaulMaly
Что значит «знает»? Это ведь смотря как писать. Если вы пишете в «event-driven» стиле, то «знает» это слишком громко.
Лично для меня возможность подписываться на изменения в хранилище было бы хорошим юзкейсом. Даже в том примитивном виде как сейчас работает между вкладками. Опять же главный вопрос, почему нет? (и атомарность тут ни при чем).
Frozik
Ну для этого и можно использовать библиотеки, на подобие того, что создал автор данного поста. См. коммент выше.
PaulMaly
Да причем тут библиотеки то? Лично я давно и вполне успешно использую localForage от мазилы. Но вопрос то опять не в этом. Если ивент уже есть, почему он так искусственно ограничен?