LocalStorage в JavaScript: подробное руководство

Александр Мальцев
Александр Мальцев
90K
21
Содержание:
  1. Общие сведения о localStorage и sessionStorage
  2. localStorage vs cookies
  3. Безопасность данных
  4. Работа с localStorage и sessionStorage
  5. Событие storage
  6. Примеры использования localStorage
  7. Задачи
  8. Комментарии

В этой статье рассмотрим технологии localStorage и sessionStorage, которые предназначены для хранения данных в формате ключ-значение непосредственно в браузере.

Общие сведения о localStorage и sessionStorage

LocalStorage и sessionStorage – это веб-хранилища, находящиеся в браузере пользователя и предназначенные для хранения данных.

Хранение информации в этих объектах осуществляется в формате «ключ-значение». Ключ и значение – это всегда строки.

Т.е., по сути, каждое хранилище представляет собой вот такой объект:

{
  'key1': 'value1',
  'key2': 'value2',
  'key3': 'value3',
  ...
}

Если в качестве значения указать не строку, а какой-то другой тип данных, например, объект, то он будет, перед тем как туда записан, автоматически преобразован в строку (т.е. так как будто мы для него явно вызвали метод toString()).

Таким образом, в localStorage и sessionStorage:

  • данные хранятся в виде пар «ключ-значение»;
  • хранить можно только строки;
  • если необходимо сохранить в эти хранилища массивы и объекты, то перед тем, как это сделать их нужно их сначала преобразовать в строки, например, используя метод JSON.stringify() (для обратного преобразования использовать JSON.parse()).

Где можно увидеть эти хранилища?

Например, в Google Chrome для этого необходимо открыть «Инструменты разработчика», перейти на вкладку «Application». Здесь они находятся на левой панели в разделе «Storage». При выборе источника вы увидите какие данные содержатся соответственно в sessionStorage и localStorage.

sessionStorage vs localStorage

SessionStorage хранит данные только во время текущей сессии (для вкладки, пока она открыта). Закрытие вкладки или браузера приводит к очищению этих данных. При этом данные сохраняются при обновлении страницы или отображение в этой вкладке другой страницы из этого же источника.

В отличие от sessionStorage, localStorage хранит данные в течение неограниченного количества времени. Они сохраняются при закрытии браузера и выключения компьютера. Но, хоть эти данные могут храниться бесконечно в браузере, обычный пользователь может их удалить, например выполнив очистку истории (при включенной опции «файлы cookie и другие данные сайтов»).

localStorage vs cookies

Cookie и localStorage используются для хранения информации в браузере.

Но что лучше использовать в том или ином случае? Чтобы в этом вопросе ориентироваться необходимо знать различия между ними:

  • по месту хранения (куки и localStorage хранятся на компьютере пользователя в браузере);
  • по размеру (cookies ограничены 4 Кбайт, а localStorage – 5 Мбайт);
  • по включению этих данных в HTTP-заголовок (куки в отличие от данных локального хранилища включаются в состав запроса при отправке его на сервер, а также сервер их может добавлять в ответ при отправке его клиенту; таким образом cookies являются частью HTTP-протокола, и увеличивают объём передаваемых данных от клиента серверу и обратно);
  • по доступности данных (печеньки можно прочитать и установить как на сервере, так и на клиенте; на клиенте доступны все куки, кроме тех, у которых установлен флаг HttpOnly; localStorage доступен только в браузере посредством JavaScript API;
  • по времени хранения данных (куки хранятся ограниченное время (до конца сеанса или истечения указанной даты), нахождение данных в локальном хранилище не ограничено по времени);
  • по удобству использования в JavaScript (работа с localStorage в JavaScript организовано намного удобнее чем с cookie);
  • по необходимости информирования пользователей Евросоюза (при использовании cookies сайт в ЕС должен получать на это разрешение от пользователей; для данных локального хранилища это не требуется);
  • по назначению (куки в основном используются для управления сеансом, персонализации и отслеживания действий пользователя, в то время как localStorage применяется в качестве обычного локального хранилища информации на компьютере пользователя).

Что использовать: localStorage или cookie? На самом деле, ответ на этот вопрос очень прост. Если данные нужны на стороне сервера, то в этом случае лучше использовать cookie. Т.к. куки отправляются с каждым HTTP-запросом на сервер, а также их там можно установить (они добавляются в ответ и браузер при его получении их сохранит).

Если вы работаете с данными только на клиенте (в браузере), то тогда более предпочтительно использовать localStorage.

Безопасность данных

Хранилище localStorage привязана к источнику (домену, протоколу и порту). Данные, находящиеся в некотором источнике, доступны только на страницах этого же источника. К данным другого источника обратиться нельзя.

SessionStorage ограничена вообще одной вкладкой браузера. Это означает, что с помощью JavaScript нельзя получить доступ к данным другой вкладки даже если она имеет тот же источник.

Работа с localStorage и sessionStorage

Объекты localStorage и sessionStorage являются свойствами глобального объекта window. А это значит к ним можно обращаться соответственно как window.localStorage и window.sessionStorage, или просто localStorage и sessionStorage.

Для работы с localStorage и sessionStorage нам доступен одинаковый набор свойств и методов:

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

Событие storage

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

Данное событие возникает на объекте window:

window.addEventListener('storage', event => {
  console.log(event);
});

Если посмотреть объект event, то среди свойств можно увидеть следующие:

  • key – ключ, значение которого изменено (возвращает null при очистке хранилища);
  • oldValue – предыдущее значение (null – если ключ только что был добавлен);
  • newValue – новое значение (null – при удалении ключа);
  • storageArea – изменённый объект-хранилище;
  • url – url документа, в котором произошло обновление хранилища.

Создадим пример, который будет следить за изменениями в localStorage и обновлять в соответствии с ними данные на страницах.

Для этого создадим две страницы (например, «page-1.html» и «page-2.html») и поместим в них следующий код:

  <div id="list">
  <button type="button">Добавить</button>
  <ul></ul>
</div>

<script>
  const elementList = document.querySelector('#list');
  const elementBtn = elementList.querySelector('button');
  const elementUl = elementList.querySelector('ul');

  function updateStorage() {
    const data = [];
    for (let element of elementUl.querySelectorAll('li')) {
      data.push(element.textContent);
    }
    localStorage['items'] = JSON.stringify(data);
  }

  function updateUl(items) {
    const html = [];
    for (let item of items) {
      html.push(`<li>${item}</li>`);
    }
    elementUl.innerHTML = html.join('');
  }

  elementBtn.onclick = () => {
    const elementsLi = elementUl.querySelectorAll('li');
    const newLi = document.createElement('li');
    newLi.textContent = elementsLi.length + 1;
    elementUl.append(newLi);
    updateStorage();
  }

  window.onstorage = event => {
    updateUl(JSON.parse(event.newValue));
  }
</script>

Примеры использования localStorage

1. Добавим ключ в localStorage, после этого получим его значение, а затем удалим:

// добавим в localStorage ключ «bgColor» со значением «green»
localStorage.setItem('bgColor', 'green');
// получим значение ключа «bgColor» и сохраним его в переменную «bgColor»
const bgColor = localStorage.getItem('bgColor');
// удалим ключ «bgColor»
localStorage.removeItem('bgColor');

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

localStorage['bgColor'] = 'green';
const bgColor = localStorage['bgColor'];
delete localStorage['bgColor'];

2. Удалим все элементы из хранилища localStorage:

localStorage.clear();

3. Переберём все ключи, находящиеся в localStorage:

// localStorage.length - количество ключей в хранилище
for (let i = 0, length = localStorage.length; i < length; i++) {
  // ключ
  const key = localStorage.key(i);
  // значение
  const value = localStorage[key];
  console.log(`${key}: ${value}`);
}

4. Пример, в котором сохраним объект в localStorage:

// объект
const obj = {
  prop1: 'value1',
  prop2: 'value2',
  prop3: 'value3'
}

//сохраним объект в LocalStorage предварительно преобразовав его в строку JSON
localStorage['mykey'] = JSON.stringify(obj);
// если ключ «mykey» имеется в localStorage, то...
if (localStorage['mykey'] {
  // получим из LocalStorage значение ключа «mykey» и преобразуем его с помощью метода JSON.parse() в объект
  const newObj = JSON.parse(localStorage['mykey']);
}

В этом коде сохранение объекта выполняется посредством его сериализации в строку JSON посредством JSON.stringify().

5. Проверим поддерживает ли браузер веб-хранилища?

if (typeof(Storage) !== 'undefined') {
  // поддерживает localStorage
} else {
  // браузер не поддерживает веб-хранилище
}

6. Попробуем добавить ключ в localStorage, но если в хранилище закончилось место (QUOTA_EXCEEDED_ERR), то выведем в консоль сообщение об этом:

try {
  localStorage['theme'] = 'dark';
} catch (e) {
  if (e == QUOTA_EXCEEDED_ERR) {
    console.log('Не достаточно места в localStorage');
  }
}

7. Добавим дату срока действия к элементам, которую затем будем использовать для их очистки (удалять те из них дата срока действия которых превышает текущую):

// данные полученные из localStorage
const data = [
  {
    id: '1608467',
    title: '6.26" Смартфон Huawei Nova 5T 128 ГБ фиолетовый',
    timestamp: 1583020800000 // 01.03.2020
  },
  {
    id: '1348312',
    title: '6.1" Смартфон Huawei P30 128 ГБ синий',
    timestamp: 1585872000000 // 03.04.2020
  },
  {
    id: '1394820',
    title: '6.1" Смартфон Apple iPhone 11 128 ГБ черный',
    timestamp: 1586476800000 // 10.04.2020
  }
];
// новый массив
const newData = [];

// добавим в newData элементы, значение timestamp у которых больше текущей даты
newData.forEach(element => {
  if (element.timestamp > Date.now()) {
    newData.push(element);
  }
});

// сохраним newData в LocalStorage
localStorage.setItem('items', JSON.stringify(newData));

Задачи

1. Записать момент, на котором пользователь остановился при просмотре видео в localStorage, а затем восстанавливать его при открытии страницы.

2. Сохранить данные формы в хранилище, а затем восстановить их при перезагрузки страницы.

3. Написать код, сохраняющий историю просмотров страниц сайта в localStorage.

Комментарии:

  1. Toivo
    Toivo
    14.09.2021, 11:56
    сли в качестве значения указать не строку, а какой-то другой тип данных, например, объект, то он будет, перед тем как туда записан, автоматически преобразован в строку (т.е. так как будто мы для него явно вызвали метод toString()).

    «Если»
    1. Александр Мальцев
      Александр Мальцев
      14.09.2021, 15:06
      Спасибо! Поправил.
    2. Stanislav
      Stanislav
      16.06.2020, 17:07
      Здавствуйте, ситуация такова, нужно отследить ссылку по которой пользователь попал на сайт и записать в скрытое поле ввода, при этом есть условие, он может переходить по страницам сайта, но нужна именно ссылка по которой он папал на сайт, я пробовал использовать данный код, но получается записать только последнюю ссылку с которой перешли на страницу:
      $(document).ready(function() {
       sessionStorage.setItem('link', document.referrer);
        var sessionref = sessionStorage.getItem('link');
        if (sessionref) {
          $('input[name ="referer"]').val(sessionref);
        } else {
        $('input[name ="referer"]').val('error');
        }
      });
      

      Может подскажете решение, если оно существует?
      1. Александр Мальцев
        Александр Мальцев
        17.06.2020, 08:51
        Привет! sessionStorage сохраняет данные только в пределах вкладки. Если пользователь откроет ссылку в новой вкладке, то там этих данных уже не будет.

        В коде вам нужно сначала проверить, если ли данные в LocalStorage, а потом туда уже что-то записывать:
        $(function() {
          var sessionref = sessionStorage.getItem('link');
          if (sessionref === null) {
            sessionref = document.referrer;
            sessionStorage.setItem('link', sessionref);
          }
          if (sessionref) {
            $('input[name ="referer"]').val(sessionref);
          } else {
          $('input[name ="referer"]').val('error');
          }
        });
        
      2. Nik
        Nik
        12.04.2020, 13:32
        Разница в быстродействии очевидна, теперь ясно почему не cookie. Хорошая статья, наглядно видно!
        1. Александр Мальцев
          Александр Мальцев
          12.04.2020, 14:00
          На это не стоит ориентироваться, сейчас результаты могут быть другими. Это зависит от того, как это физически реализовано в конкретном браузере. Если стоит выбор, то лучше просто задать себе вопрос: «Нужны ли мне эти данные на сервере и буду ли я их как-то учитывать при строительстве страницы на стороне сервера? Если нет, то тут однозначно LocalStorage.
        2. Дмитрий
          Дмитрий
          07.06.2019, 22:41
          Здравствуйте Александр, использую на одном из своих шаблонов http://laraweb.ru/autoshop/shop/ переключатель — сетка/список, сделал сохранение переключения через localStorage, но возникла проблема, там слева фильтр на аджакс, когда я делаю выборку, нажимаю найти, то мне выдается результат товаров, но при этом перестает работать переключатель список/сетка, можно ли как то решить проблему, чтоб сохранялся рабочий переключатель?
          1. Николай
            Николай
            08.03.2017, 10:06
            Спасибо за статью, такой вопрос, а где физически сохраняются данные? И нельзя ли где-то в переменных это прописывать. А также, файлы куки как мы знаем легко очищаются в винде, что с этими данными? Ну и еще, если я сделал мобильное приложение на основе HTML5, где там сохраняются данные?
            1. Александр Мальцев
              Александр Мальцев
              08.03.2017, 16:02
              Это зависит от браузера. Chrome для LocalStorage использует SQLite. Физически (например, в Windows) они находятся в файлах, которые расположены каталоге: AppData\Local\Google\Chrome\User Data\Default\Local Storage\.
              Эти файлы, как и cookies можно очистить (chrome://settings/cookies#cont). Надёжное хранилище — это только база данных на сервере.
              1. Николай
                Николай
                08.03.2017, 16:59
                Спасибо за быстрый ответ, я примерно так и думал, но на всякий случай уточнил
            2. Larisa
              Larisa
              07.11.2016, 18:08
              здравствуйте, Александр! спасибо за ваш чудесный блог и оперативные ответы!
              у меня такая проблема: есть боковое меню, открытие/закрытие которого регулируется классами тэга body: site-menubar-unfold / site-menubar-fold соответственно. надо, чтобы при переходе на новую страницу выбранное состояние сохранялось. как это реализовать с помощью sessionStorage я примерно поняла, но как отследить изменение url? нагуглила только функцию hashchange, но «Событие hashchange генерируется когда изменяется идентификатор фрагмента URL (т.е. часть URL следующая за символом #, включая сам символ #).» а у меня меняется не идентификатор, а html-страница. например, localhost/project/idex.html -> localhost/project/stat.html
              спасибо)
              1. Александр Мальцев
                Александр Мальцев
                08.11.2016, 10:19
                Здравствуйте, Larisa. Спасибо за отзыв. Лучше всего событие «повесить» на момент когда происходит открытие или закрытие бокового меню. И когда это происходит сохранять состояние этого меню в localstorage. А при загрузке новой страницы считывать это состояние и устанавливать его боковому меню.
                1. Larisa
                  Larisa
                  11.11.2016, 17:40
                  вот что получилось с хранилищем, но не могу придумать, как прикрутить еще и загрузку новой страницы…
                      // получаем адрес страницы, на которой находимся
                      var pageAddress = location.href; 
                  
                      // записываем в хранилище класс, отвечающий за состояние меню
                      if ($('body').hasClass('site-menubar-unfold')){
                        sessionStorage.setItem("menuState","open"); 
                      }
                      else if ($('body').hasClass('site-menubar-fold')){
                        sessionStorage.setItem("menuState","close");
                      }
                  
                      //достаем из хранилища класс и, если он отличается от 'site-menubar-unfold', присваиваем его элементу body
                      var menuState = sessionStorage.getItem("menuState");
                      if (menuState == "close"){
                        $("body").removeClass('site-menubar-unfold');
                        $("body").addClass('site-menubar-fold');
                      }
                  
                  1. Александр Мальцев
                    Александр Мальцев
                    12.11.2016, 06:39
                    Вам необходимо разобраться каким образом класс site-menubar-unfold или site-menubar-fold появляется у элемента body. Т.е. при каком событии это происходит (например, при клике или как-то по-другому).
                    После этого вам необходимо добавить в обработчик этого события блок кода JavaScript, в котором происходит запись информации в хранилище.

                    Второй блок, в котором происходит считывание информации, необходимо выполнять после загрузки страницы:
                    $(function(){
                      // код, который выполнится после загрузки страницы
                    });
                    
                    1. Larisa
                      Larisa
                      12.11.2016, 10:48
                      классы эти появляются у элемента body по клику, но во время работы на одной странице пользователь может гонять меню туда-сюда сколько угодно — важно, какой класс у элемента body при переходе на новую страницу — т.е. при смене url — и на новую страницу этот же класс нужно перенести…
                      1. Александр Мальцев
                        Александр Мальцев
                        12.11.2016, 14:30
                        А что значит при смене url. Пользователь может попасть на страницу посредством поиска, социальных сетей или какой-то ссылки, расположенной на другом сайте. К тому же в JavaScript нет такого события. Поэтому правильно сохранять состояния меню в тот момент, когда пользователь его изменяет. Чтобы в следующий раз, когда пользователь попадёт на сайт, предоставить ему сохранённое состояние.
                        Есть событие, которое происходит при выгрузке страницы, но его поддержка зависит от браузера. Поэтому его не рекомендуется использовать. Применяется оно так:
                        $(window).unload(function() {
                          // сохраняете состояние меню
                        });
                        
                        1. Larisa
                          Larisa
                          12.11.2016, 14:46
                          еще раз большое спасибо вам! действительно, нужно было клик отслеживать)
                          а страница может меняться при переходе по ссылкам внутри нее же или в том же меню
                            //проверяем поменялся ли URL страницы в данной вкладке браузера
                            var pageAddress = location.href;
                            var oldAddress = '';
                            if (localStorage.getItem('pageAddress')) {
                              oldAddress = localStorage.getItem('pageAddress');
                            }
                            localStorage.setItem('pageAddress', pageAddress);
                          
                            var menuState = '';
                            $('#toggleMenubar').click(function(){
                              // записываем в хранилище класс, отвечающий за состояние меню
                              if ($('body').hasClass('site-menubar-unfold')){
                                localStorage.setItem('menuState', 'close');
                              }
                              else if ($('body').hasClass('site-menubar-fold')){
                                localStorage.setItem('menuState', 'open');
                              }
                            });
                            menuState = localStorage.getItem('menuState');
                          
                            if (oldAddress == pageAddress) {
                              //страница не поменялась - делаем действия, которые нам нужны при том же адресе
                              if (menuState == 'close'){
                                $("body").removeClass('site-menubar-unfold');
                                $("body").addClass('site-menubar-fold');
                              }
                            } else {
                              //страница поменялась или открыта впервые - делаем действия, которые нам нужны при новом адресе
                              if (menuState == 'close'){
                                $("body").removeClass('site-menubar-unfold');
                                $("body").addClass('site-menubar-fold');
                              }
                            }
                          
                  2. Larisa
                    Larisa
                    10.11.2016, 11:37
                    а каким образом отслеживать изменение страницы?
                2. Vlad
                  Vlad
                  08.02.2016, 17:09
                  Данные из session storage удаляются только после закрытия вкладки, закрытие браузера не удаляет данные
                  1. ctac
                    ctac
                    03.12.2015, 13:22
                    Спасибо за статью, но такой информации в сети полно, как работать, для чего нужно и тд. Вы бы провели аналитику, например чем предпочтительней использовать localStorage вместо cookie? Как перестать пользоваться cookie и перейти на localStorage? Я думаю, такой материал был бы куда интересней и полезней
                    1. Александр Мальцев
                      Александр Мальцев
                      04.12.2015, 16:59
                      Спасибо Стас за комментарий. В конце статьи добавил 2 раздела, рассказывающие и показывающие отличия между cookie и Web Storage, а также диаграммы по быстродействию.
                    Войдите, пожалуйста, в аккаунт, чтобы оставить комментарий.