LocalStorage, SessionStorage

  • Михаил
  • 12 мин. на прочтение
  • 121
  • 20 Jun 2022
  • 20 Jun 2022

LocalStorage, SessionStorage


Объекты веб-хранилища localStorage и sessionStorage позволяют хранить пары ключ/значение в браузере.

Что в них важно – данные, которые в них записаны, сохраняются после обновления страницы (в случае sessionStorage) и даже после перезапуска браузера (при использовании localStorage). Скоро мы это увидим.


Объекты хранилища localStorage и sessionStorage предоставляют одинаковые методы и свойства:

  • setItem(key, value) – сохранить пару ключ/значение.
  • getItem(key) – получить данные по ключу key.
  • removeItem(key) – удалить данные с ключом key.
  • clear() – удалить всё.
  • key(index) – получить ключ на заданной позиции.
  • length – количество элементов в хранилище.

Демо localStorage

Основные особенности localStorage:


  • Этот объект один на все вкладки и окна в рамках источника (один и тот же домен/протокол/порт).
  • Данные не имеют срока давности, по которому истекают и удаляются. Сохраняются после перезапуска браузера и даже ОС.

Например, если запустить этот код…

localStorage.setItem('test', 1);

…И закрыть/открыть браузер или открыть ту же страницу в другом окне, то можно получить данные следующим образом:

alert( localStorage.getItem('test') ); // 1

Нам достаточно находиться на том же источнике (домен/протокол/порт), при этом URL-путь может быть разным.

Объект localStorage доступен всем окнам из одного источника, поэтому, если мы устанавливаем данные в одном окне, изменения становятся видимыми в другом.

Доступ как к обычному объекту

Также можно получать/записывать данные, как в обычный объект:

// установить значение для ключа

localStorage.test = 2;

// получить значение по ключу

alert( localStorage.test ); // 2

// удалить ключ

delete localStorage.test;

Это возможно по историческим причинам и, как правило, работает, но обычно не рекомендуется, потому что:

Если ключ генерируется пользователем, то он может быть каким угодно, включая length или toString или другой встроенный метод localStorage. В этом случае getItem/setItem сработают нормально, а вот чтение/запись как свойства объекта не пройдут:


let key = 'length';
localStorage[key] = 5; // Ошибка, невозможно установить length

Когда мы модифицируем данные, то срабатывает событие storage. Но это событие не происходит при записи без setItem, как свойства объекта. Мы увидим это позже в этой главе.

Перебор ключей

Методы, которые мы видим, позволяют читать/писать/удалять данные. А как получить все значения или ключи?

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

Но можно пройти по ним, как по обычным массивам:


for(let i=0; i

Другой способ – использовать цикл, как по обычному объекту for key in localStorage.

Здесь перебираются ключи, но вместе с этим выводятся несколько встроенных полей, которые нам не нужны:


// bad try
for(let key in localStorage) {
  alert(key); // покажет getItem, setItem и другие встроенные свойства
}

…Поэтому нам нужно либо отфильтровать поля из прототипа проверкой hasOwnProperty:


for(let key in localStorage) {
  if (!localStorage.hasOwnProperty(key)) {
    continue; // пропустит такие ключи, как "setItem", "getItem" и так далее
  }
  alert(`${key}: ${localStorage.getItem(key)}`);
}

…Либо просто получить «собственные» ключи с помощью Object.keys, а затем при необходимости вывести их при помощи цикла:


let keys = Object.keys(localStorage);
for(let key of keys) {
  alert(`${key}: ${localStorage.getItem(key)}`);
}

Последнее работает, потому что Object.keys возвращает только ключи, принадлежащие объекту, игнорируя прототип.

Только строки

Обратите внимание, что ключ и значение должны быть строками.

Если мы используем любой другой тип, например число или объект, то он автоматически преобразуется в строку:


sessionStorage.user = {name: "John"};
alert(sessionStorage.user); // [object Object]

Мы можем использовать JSON для хранения объектов:

sessionStorage.user = JSON.stringify({name: "John"});

// немного позже


let user = JSON.parse( sessionStorage.user );
alert( user.name ); // John

Также возможно привести к строке весь объект хранилища, например для отладки:

// для JSON.stringify добавлены параметры форматирования, чтобы объект выглядел лучше

alert( JSON.stringify(localStorage, null, 2) );

sessionStorage

Объект sessionStorage используется гораздо реже, чем localStorage.

Свойства и методы такие же, но есть существенные ограничения:

sessionStorage существует только в рамках текущей вкладки браузера.

Другая вкладка с той же страницей будет иметь другое хранилище.

Но оно разделяется между ифреймами на той же вкладке (при условии, что они из одного и того же источника).

Данные продолжают существовать после перезагрузки страницы, но не после закрытия/открытия вкладки.

Давайте посмотрим на это в действии.

Запустите этот код…

sessionStorage.setItem('test', 1);

…И обновите страницу. Вы всё ещё можете получить данные:

alert( sessionStorage.getItem('test') ); // после обновления: 1

…Но если вы откроете ту же страницу в другой вкладке и попробуете получить данные снова, то код выше вернёт null, что значит «ничего не найдено».

Так получилось, потому что sessionStorage привязан не только к источнику, но и к вкладке браузера. Поэтому sessionStorage используется нечасто.

Событие storage

Когда обновляются данные в localStorage или sessionStorage, генерируется событие storage со следующими свойствами:

key – ключ, который обновился (null, если вызван .clear()).

oldValue – старое значение (null, если ключ добавлен впервые).

newValue – новое значение (null, если ключ был удалён).

url – url документа, где произошло обновление.

storageArea – объект localStorage или sessionStorage, где произошло обновление.

Важно: событие срабатывает на всех остальных объектах window, где доступно хранилище, кроме того окна, которое его вызвало.

Давайте уточним.

Представьте, что у вас есть два окна с одним и тем же сайтом. Хранилище localStorage разделяется между ними.

Вы можете открыть эту страницу в двух окнах браузера, чтобы проверить приведённый ниже код.

Теперь, если оба окна слушают window.onstorage, то каждое из них будет реагировать на обновления, произошедшие в другом окне.



// срабатывает при обновлениях, сделанных в том же хранилище из других документов
window.onstorage = event => {
  if (event.key != 'now') return;
  alert(event.key + ':' + event.newValue + " at " + event.url);
};
localStorage.setItem('now', Date.now());