Немного понятий и фактов

Web Storage (Веб-Хранилище) — это технология хранения данных на стороне клиента прямиком в браузере.

Два объекта — две идеи

Веб-хранилище подразделяется на два типа:

Local Storage

Локальное хранилище — это объект localStorage, используемый для хранения данных вида «Ключ - Значение» на постоянной основе. Иначе говоря, данные хранятся до тех пор, пока их принудительно не заставят уйти, то есть удалят.

Session Storage

Хранилище данных сеансов — это объект sessionStorage, используемый для хранения данных вида «Ключ - Значение» на временной основе. Данные хранятся до тех пор, пока не будет закрыта вкладка или окно браузера.

Что можно хранить и для чего использовать?

Хранить можно всё то, что сможет уложиться в строку, так как единственным разрешенным типом данных для хранения является текстовый тип — строка.

Навскидку, веб-хранилище можно забивать следующими данными:

  • Состояние работы приложения — Например, последний открытый документ, значение измененного поля ввода или история поиска по сайту.
  • Настройки пользователя — Например, выбранная тема оформления сайта или вид отображения информации.
  • Сохранение пользовательских данных при неудачной попытке отправки на сервер.
  • Запись данных по мере их ввода — Например, редактор текста StackEdit.

Внимание!

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

Поддержка браузеров

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

Web-Storage поддержка браузерами

Оценить всю сложившуюся на данный момент ситуацию можно на сайте Can I Use.

Доступный размер

В отличии от печенек (HTTP cookie), веб-хранилище предоставляет намного больший размер — 4Кб против ~5Мб.

Проведя небольшой тест на реальных устройствах, получаем следующие данные:

  • Chrome 38, FireFox 33 и Opera 25 — размер хранилища 5000 Кб.
  • IE8-11 — размер хранилища 4750 Кб.
  • iOS 5-8.1 Safari, OS X Safari — размер хранилища 2500 Кб.
  • Android 4.x-5 — размер хранилища 5000 Кб.
  • Windows Phone 7.8 — размер хранилища 4750 Кб.

Устройства проверялись с «заводскими» настройками браузера, то есть никаких настроек до тестирования не проводилось. Протестировать ваше устройство можно используя вот «этот» скрипт.

Работаем с данными

Рассмотрим традиционное использование объекта localStorage и не совсем традиционное.

Объектом sessionStorage мы заниматься не будем, так как единственное различие с localStorage — это срок хранения данных. Все методы и свойства объекта одинаковые, и для работы с хранилищем данных сеансов необходимо лишь заменить объект в коде.

Пример — Запись данных в хранилище

Записать данные в хранилище можно тремя способами:

localStorage.setItem("key", "value");
// Или
localStorage.key = "value";
// Или
localStorage["key"] = "value";

Пример — Чтение данных из хранилища

Считать данные из хранилища также просто как и записать:

localStorage.getItem("key");
// Или
localStorage.key;
// Или
localStorage["key"];

Пример — Удаление данных из хранилища

Удаление данных имеет всего один синтаксис:

localStorage.removeItem("key");

Пример — Удаление всех данных из хранилища

Если вдруг вам надоело записывать и считывать данные в веб-хранилище, то в любой момент вы можете остановить это, удалив все записи:

localStorage.clear();

Пример — Количество записей в хранилище

Для того, чтобы получить общее количество записей в хранилище, необходимо использовать стандартное свойство length:

localStorage.length;

Пример — Получение всех записей хранилища

Получить все данные, записанные в хранилище, можно с помощью цикла:

for (var i = 0; i < localStorage.length; i++) {
  var key = localStorage.key(i);
  console.log(key + ' = ' + localStorage[key]);
}

В цикле перебираются все элементы хранилища, получаются их ключи и значения.

Пример — Хранение не строковых данных

Если есть необходимость хранить в локальном хранилище не только строковые данные, то нужно учесть, что придётся заранее позаботиться об их преобразовании:

// В хранилище:
// a = "11"
// b = "19"
// c = "25"

Мы хотим сумму всех имеющихся элементов. Получаем:

var sum = 0;

for (var i = 0; i < localStorage.length; i++) {
  var key = localStorage.key(i);
  sum += Number(localStorage[key]);
}

console.log(sum);

Просто используем для этого функцию Number.

Если имеем дело с датой, то придется использовать объект Date:

// В хранилище:
// date = "2014-10-30"

var data = localStorage["date"].split('-');
var data = new Date(data[0], data[1], data[2]);
console.log(data.getDate() + ' ' + data.getMonth() + ' ' + data.getFullYear());

Если перед записью есть возможность отформатировать дату в текстовую строку, то лучше сделать так:

// Запись
var currentTime = new Date();
localStorage["date"] = currentTime.getFullYear() + '/' + currentTime.getMonth()
                                                 + '/' + currentTime.getDate();

// Чтение
var data = new Date(localStorage["date"]);
console.log(data.getDate() + ' ' + data.getMonth() + ' ' + data.getFullYear());

Пример — Записываем в хранилище массив

Вы не забыли, что веб-хранилище дружит только со строками? Нам нужно больше функционала. Исправляем.

Схема махинаций:

  • Преобразование массива в строку.
  • Запись строки в хранилище.
  • Чтение строки из хранилища.
  • Преобразование строки в массив.

Пффф. Легко!

На входе у нас есть массив:

var myArray = ["One", "Two", ["One", "Two"], "four"];

Преобразуем его в строку, используя JSON.stringify, и записываем в хранилище:

localStorage["myArray"] = JSON.stringify(myArray);

Для внутреннего удовлетворения посмотрим, что выведет console.log():

console.log(localStorage["myArray"]);
// Вывод: ["One","Two",["One","Two"],"four"]

Спустя сто и один день, мы обращаемся к хранилищу и хотим заполучить наш массив обратно:

var data = JSON.parse(localStorage["myArray"]);

И снова нужно успокоить в себе параноика тем, что ожидаемое получено в необходимой форме:

console.log(data);
// Вывод:
// ["One", "Two", Array[2], "four"]
// 0: "One"
// 1: "Two"
// 2: Array[2]
// 3: "four"
// length: 4
// __proto__: Array[0]

Таким путём можно пойти и при необходимости записи объектов в веб-хранилище:

// Входные данные
var article = {
  user: 'mrmlnc',
  date: '30-10-2014',
  star: '-1'
};

// Записываем
localStorage["post_0"] = JSON.stringify(article);

// Считываем
var post = JSON.parse(localStorage["post_0"]);

// Выводим
console.log(post);

Очень удобно и практично.

К слову, редактор StackEdit хранит так настройки и сами записи:

{
  "layoutOrientation":"horizontal",
  "editMode":"ltr",
  "lazyRendering":true,
  "editorFontClass":"font-rich",
  "fontSizeRatio":1,
  "maxWidthRatio":1,
  "cursorFocusRatio":0.5,
  "defaultContent":"\n\n\n> Written with [StackEdit](https://stackedit.io/).",
  ...
}

В реальной жизни это выглядит так:

StackEdit LocalStorage Data

Пример — Отслеживание изменения хранилища

Веб-хранилище генерирует событие onStorage на каждое своё изменение: добавление, изменение или удаление.

Вешаем прослушку на событие:

// Функция обработчика события
function storageChanged(storageEvent) {
  alert('Событие Storage от' + storageEvent.url + '!');
};

window.addEventListener('storage', storageChanged, false);

Кстати, объект, который передается функции обработчика событий, содержит в себе немного полезной информации:

key

Ключ измененной, добавленной или удаленной записи.

oldValue

Значение ключа до изменения.

newValue

Значение ключа после изменения.

url

URL страницы, которая породила событие onStorage.

storageArea

localStorage или sessionStorage, в зависимости от того, где произошло изменение.

Стоит учитывать тот факт, что событие вызывается на всех страницах, кроме той, что его породило. Пример работы можно посмотреть на сайте html5demos.

Выводы

По сути дела, это круто!

Web Storage — это просто ещё один шаг к оффлайн HTML5 приложениям. Уже сейчас вы можете хранить настройки своих веб-приложений в удобном для вас виде прямиком в браузере. Не маловажной ступенью дальнейшего развития вашего проекта будет сохранение введенных данных пользователя, при неудачной попытке отправки на сервер или валидации, и последующего использования их при повторном заполнении. Именно для этого можно использовать объект sessionStorage. Согласитесь — не это ли будущее отзывчивых приложений? Я уже не представляю себе повторный ввод всех полей в форме, если была допущена ошибка ранее и страница обновилась.

Кратко о плюсах веб-хранилища:

  • Достаточно большой объем хранилища.
  • Приличная скорость.
  • Неограниченное время жизни.
  • Удобный интерфейс общения с данными.