Как работать с localstorage в javascript

Usage

unless localStorage?{LocalStorage} =require('')localStorage =newLocalStorage('./scratch')localStorage.setItem('myFirstKey', 'myFirstValue')console.log(localStorage.getItem('myFirstKey'))localStorage._deleteLocation()

Open or create and add these two lines:


// /src/setupTests.jsimport { LocalStorage } from "node-localstorage";global.localStorage = new LocalStorage('./scratch');
if (typeof localStorage === "undefined" || localStorage === null) {  var LocalStorage = require('node-localstorage').LocalStorage;  localStorage = new LocalStorage('./scratch');}localStorage.setItem('myFirstKey', 'myFirstValue');console.log(localStorage.getItem('myFirstKey'));

Polyfil your node.js environment with this as the global localStorage when launching your own code

node -r node-localstorage/register my-code.js

Overview of web storage

Web storage is data stored locally in a user’s browser. There are two types of web storage:

  • Local storage — data with no expiration date that will persist after the browser window is closed.
  • Session storage — data that gets cleared after the browser window is closed.

This is useful for saving data such as user preferences (light or dark color theme on a website), remembering shopping cart items, or remembering a user is logged into a website.

Previously, cookies were the only option for remembering this type of local, temporary data. Local storage has a significantly higher storage limit (5MB vs 4KB) and doesn’t get sent with every HTTP request, so it can be a better option for client-side storage.

Here is an overview of methods.

Method Description
Add key and value to local storage
Retrieve a value by the key
Remove an item by key
Clear all storage

You can test out what’s in local storage by going to the JavaScript console and typing it in. Actually do this, don’t just read it.

Adding some data to is as easy as using the method. I’ll use a generic key and value for the names, but they can be any strings.

Now if you test in the console again, you’ll find your new key and value.

If you want to get the value for a particular key, you’ll use the method.

Finally, you can remove the data with .

Using will clear all local storage.

Now we can begin setting up the app.

API IndexedDB

IndexedDB

▍Внутренние механизмы IndexedDB

политике одного источникавеб-воркерах

  • Базы данных IndexedDB хранят данные в формате ключ/значение. Значения могут быть сложно структурированными объектами, а ключи могут быть свойствами таких объектов. Индексы можно создавать на основе любого свойства объекта, что способно ускорить поиск данных и упростить их сортировку. Ключи, кроме того, являются двоичными объектами.
  • СУБД IndexedDB построена на базе транзакционной модели. Все операции, выполняемые с базой данных, всегда происходят в контексте . В результате, например, нельзя выполнять команды или открывать курсоры за пределами транзакций. Кроме того, транзакции подтверждаются автоматически, вручную их подтверждать нельзя.
  • API IndexedDB, по большей части, является асинхронным. Это API не предоставляет запрошенные данные, просто возвращая их в ответ на какую-то команду. Вместо этого при запросе данных нужно передать соответствующему методу функцию обратного вызова. Синхронный подход не используется ни для сохранения данных в базу, ни для их загрузки из неё. Вместо этого приложение выполняет запрос к базе данных, описывающий требуемую операцию. После завершения операции возникает событие, оповещающее приложение о том, что операцию либо удалось выполнить, либо нет. Этот подход не особенно отличается от работы API XMLHttpRequest, или многих других механизмов JavaScript.
  • В IndexedDB используется множество запросов. Запросы — это объекты, которые принимают события об успешном или неуспешном завершении операции. У них есть свойства и , которым можно назначать прослушиватели соответствующих событий, а так же — свойства , , , анализируя которые можно узнать о состоянии запроса.
  • IndexedDB — это объектно-ориентированная база данных. Это не реляционная СУБД, таблицы которой представляют собой коллекции строк и столбцов. Эта фундаментальная особенность влияет на то, как проектируют и создают приложения, использующие IndexedDB.
  • IndexedDB не использует SQL. В этой СУБД применяются запросы к индексам, возвращающие курсоры, которые используются для работы с наборами данных, являющимися результатами запросов. Если вы не знакомы с NoSQL-системами, взгляните на этот материал.
  • К IndexedDB-хранилищам применяется политика одного источника. Источник — это комбинация домена, протокола и порта URL документа, в котором выполняется скрипт. Каждый источник может работать только с собственным набором баз данных, при этом у каждой базы данных есть уникальное имя, идентифицирующее её в пределах баз одного источника.

▍Ограничения IndexedDB

  • Сортировка данных с учётом особенностей различных языков. Не во всех языках строки сортируют одинаково, и IndexedDB не поддерживает сортировку с учётом особенностей различных языков. При этом, хотя база данных не может выполнять подобную сортировку, информацию, полученную из базы, можно сортировать средствами приложения.
  • Синхронизация. API не проектировалось с учётом возможности синхронизации локальной базы с сервером. Такая синхронизация, конечно же, возможна, но соответствующие механизмы разработчику придётся реализовывать самостоятельно.
  • Полнотекстовый поиск. API IndexedDB не поддерживает чего-то вроде оператора LIKE из SQL.
  • Пользователь отдал команду на удаление данных. Многие браузеры имеют разделы настроек, в которых есть средства, позволяющие пользователю удалить все данные, сохранённые для некоего веб-сайта, включая куки, закладки, сохранённые пароли, и данные IndexedDB.
  • Браузер работает в анонимном режиме. Такие режимы называются в разных браузерах по-разному. В Chrome это «режим инкогнито», в Firefox — «приватный режим». После завершения анонимной сессии браузер удалит базу данных.
  • Переполнение диска или достижение некоего заданного лимита.
  • Повреждение данных.

Поддержка IndexedDB различными браузерами

示例

这里我们通过调用 来访问一个 对象。首先,使用  测试本地存储中是否包含该数据项。如果包含,则运行 函数,该函数使用  来获取数据项,并使用这些值更新页面样式。如果不包含,我们运行另一个函数 ,该函数使用 设置数据项,然后运行 。

if(!localStorage.getItem('bgcolor')) {
  populateStorage();
} else {
  setStyles();
}

function populateStorage() {
  localStorage.setItem('bgcolor', document.getElementById('bgcolor').value);
  localStorage.setItem('font', document.getElementById('font').value);
  localStorage.setItem('image', document.getElementById('image').value);

  setStyles();
}

function setStyles() {
  var currentColor = localStorage.getItem('bgcolor');
  var currentFont = localStorage.getItem('font');
  var currentImage = localStorage.getItem('image');

  document.getElementById('bgcolor').value = currentColor;
  document.getElementById('font').value = currentFont;
  document.getElementById('image').value = currentImage;

  htmlElem.style.backgroundColor = '#' + currentColor;
  pElem.style.fontFamily = currentFont;
  imgElem.setAttribute('src', currentImage);
}

备注:要运行完整的例子,可查看 Web Storage Demo。

Веб-хранилище. Назначение localStorage и sessionStorage

Веб-хранилище — это данные, хранящиеся локально в браузере пользователя. Существует 2 типа веб-хранилищ:

  • LocalStorage;
  • SessionStorage.

В них вы можете хранить информацию в формате ключ-значение. Ключ и значение – это всегда строки.

Если мы попытаемся сохранить в значение элемента хранилища другой тип значений, например, объект, то он будет, перед тем как туда записан, преобразован в строку. В данном случае посредством неявного у него вызова метода . Т.е. в значении элемента этих хранилищ кроме строкового типа данных никакого другого содержаться не может.

Отличие между этими хранилищами сводится только к периоду времени, в течение которого они могут хранить данные, помещенные в них:

  • SessionStorage – выполняет это в течение определённого промежутка времени (сессии). Закрытие вкладки или браузера приводит их к удалению. При этом данные в SessionStorage сохраняются при обновлении страницы.
  • LocalStorage – осуществляет это в течение неограниченного времени. Они сохраняются при перезагрузке браузера и компьютера. Их длительность хранения ничем не ограничена. Но, хоть эти данные могут храниться бесконечно в браузере, обычный пользователь может их очень просто удалить, например выполнив очистку истории (при включенной опции «файлы cookie и другие данные сайтов»).

Хранилище LocalStorage похоже на cookies. Оно также применяется для хранения данных на компьютере пользователя (в браузере). Но кроме общих сходств имеется также и много отличий.

Cookies vs. LocalStorage: В чём разница?

Отличия между cookies и LocalStorage:

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

Что использовать: LocalStorage или cookies? На самом деле, ответ на этот вопрос очень прост. Если вам не нужно отправлять данные с каждым HTTP-запросом на сервер, то в этом случае лучше использовать для хранения данных LocalStorage.

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

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

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

Итоги

Основные характеристики LocalStorage и SessionStorage:

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

Integrating local storage

Now we’re going to add a few more bits of functionality to the app. First, every time the form is submitted, the value should be added to the as well as appear on the front end. We’ll also want to loop through all the existing local storage items and display them at the top of the list. Last, we want the «Clear All» button to remove all items from local storage as well as the front end.

Let’s create an empty array to start, and create a key called «items». Now, only supports strings as values, and want to store our to-dos in an array.

We can get around this by using to convert a data array to a string. We’ll use to convert the contents of back into something we can work with later in the variable. Put this code below all the constant declarations we set earlier.

scripts.js

In the form event listener, let’s push any new value into the array, then set the to the new, updated value.

scripts.js

We’re going to loop through everything in our variable above, which contains all the existing data in a form JavaScript can understand and work with, and we’ll run the again. This will display all existing stored information on the front end every time we open the app.

scripts.js

Last, we’ll add a click event to the button that will clear all data from , as well as removing every child node from the .

scripts.js

If all went well, everything will save to storage as well as appear on the front end, which you can check by testing in the console.

There’s one final problem: after closing the browser or reloading the page, all the existing information in is gone, and nothing remains on the front end. Why?

Our is being reset to an empty array every time the script runs. We could fix this by making a conditional statement that checks if already exists, such as in the below example.

scripts.js

A little more concise would be to use a to do the same thing.

scripts.js

With that, our app is complete! Now when you enter in some information and refresh or close the browser window, the data will persist until you manually clear the data in Developer Tools (under Application -> Storage) or by running the command. Here is the full JavaScript code.

scripts.js

Here is the demo and source code once again.

  • View Demo
  • View Source

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

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

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

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

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

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

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

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


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

Callbacks vs Promises

Here’s an example of the Node-style callback form:

localforage.setItem('key', 'value', function (err) {
  // if err is non-null, we got an error
  localforage.getItem('key', function (err, value) {
    // if err is non-null, we got an error. otherwise, value is the value
  });
});

And the Promise form:

localforage.setItem('key', 'value').then(function () {
  return localforage.getItem('key');
}).then(function (value) {
  // we got our value
}).catch(function (err) {
  // we got an error
});

Or, use /:

try {
    const value = await localforage.getItem('somekey');
    // This code runs once the value has been loaded
    // from the offline store.
    console.log(value);
} catch (err) {
    // This code runs if there were any errors.
    console.log(err);
}

Підтримка веб-переглядачами

Таблиця сумісності на цій сторінці створена зі структурованих даних. Якщо ви хочете долучитися до розробки цих даних, пропонуйте нам свої pull request до репозиторію https://github.com/mdn/browser-compat-data.

Update compatibility data on GitHub

Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Firefox for Android Opera for Android Safari on iOS Samsung Internet
Chrome Full support 4 Edge Full support 12 Firefox Full support 3.5 IE Full support 8 Opera Full support 10.5 Safari Full support 4 WebView Android Full support ≤37 Chrome Android Full support 18 Firefox Android Full support 4 Opera Android Full support 11 Safari iOS Full support 3.2 Samsung Internet Android Full support 1.0

Событие storage

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

  • – ключ, который обновился (, если вызван ).
  • – старое значение (, если ключ добавлен впервые).
  • – новое значение (, если ключ был удалён).
  • – url документа, где произошло обновление.
  • – объект или , где произошло обновление.

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

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

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

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

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

Обратите внимание, что событие также содержит: – url-адрес документа, в котором данные обновились. Также содержит объект хранилища – событие одно и то же для и , поэтому ссылается на то хранилище, которое было изменено

Мы можем захотеть что-то записать в ответ на изменения

Также содержит объект хранилища – событие одно и то же для и , поэтому ссылается на то хранилище, которое было изменено. Мы можем захотеть что-то записать в ответ на изменения.

Это позволяет разным окнам одного источника обмениваться сообщениями.

Современные браузеры также поддерживают Broadcast channel API специальный API для связи между окнами одного источника, он более полнофункциональный, но менее поддерживаемый. Существуют библиотеки (полифилы), которые эмулируют это API на основе и делают его доступным везде.

Резюме.

DOM Storage и аналогичные системы хранения — важный шаг к offline-работе web-приложений.

DOM Storage поддерживается всеми современными браузерами.

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

Offline-хранилище может быть использовано для сохранения сложных состояний интерфейса — размеров окон, контрольных элементов и т.п.

Все изменения интерфейса посетителем мгновенно сохранятся в DOM Storage и восстановятся при следующем заходе на страницу без дополнительных механизмов сохранения интерфейса на сервере.

Объекты localStorage и sessionStorage

Работа с веб-хранилищами в JavaScript выполняется через объекты и . Объекты и находятся в глобальном объекте .

Они имеют одинаковый набор свойств и методов:

  • — получить значение элемента хранилища по ;
  • — установить для указанное значение (если в хранилище уже есть данные с этим ключом, то они будут переписаны);
  • — удалить элемент по ;
  • — удалить все элементы;
  • — получить элемент по его индексу (в основном используется для перебора);
  • — свойство, с помощью которого можно получить количество элементов в хранилище;

Примеры

1. Пример, в котором добавим элемент в веб-хранилище, получим его значение по ключу, а затем удалим его:

// 1 - добавим в LocalStorage элемент с ключом «bgColor» и значением «green»
localStorage.setItem('bgColor', 'green');
// 2 - получим значение по ключу «bgColor» и сохраним его в переменную «bgColor»
var bgColor = localStorage.getItem('bgColor');
// 3 - удалим элемент из хранилища по ключу
localStorage.removeItem('bgColor');

2. Пример, в котором удалим все элементы из хранилища:

localStorage.clear();

3. Пример, в котором перебём все элементы LocalStorage:

<div id="result"></div>
...
<script>
  var output = '';

  // localStorage.length - количество элементов в хранилище
  for (var i = 0, length = localStorage.length; i < length; i++) {
    // localStorage.key(i) - получение ключа элемента по его индексу
    output += 'Ключ: ' + localStorage.key(i) + "; Значение: " + localStorage.getItem(localStorage.key(i)) + ".&lt;br&gt;";
  }
  
  document.querySelector('#result').innerHTML = output;
</script>

4. Пример, в котором запишем JavaScript объект в LocalStorage:

// 1 - JavaScript объект
var obj = {
  prop1: 'value1',
  prop2: 'value2',
  prop3: 'value3'
  // ...
}
// 2 - Сохраним JavaScript объект в LocalStorage преобразовав его в строку JSON
localStorage.setItem('mykey', JSON.stringify(obj));

// ...

// 3 - Получим из LocalStorage значение по ключу «mykey», если он там есть (т.е. если его значение не равно null)
if (localStorage.getItem('mykey')) {
  // 4 - Получим из LocalStorage значение по ключу «mykey», преобразуем его с помощью метода JSON.parse в JavaScript объект
  obj = JSON.parse(localStorage.getItem('mykey'));
}

Из этого примера видно, что если вам нужно в LocalStorage записать объект, то одним из вариантов решения этой задачи может стать его сериализация в строку JSON с помощью функции .

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

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

6. Пример, в котором покажем как можно добавить дату к записям, а затем её использовать для их очистки (например, удалять записи, если со времени её записи прошло уже более 30 дней):

// пример данных, которые мы получили из LocalStorage
var
  viewsItems = [
    {
      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
    }
  ],
  newViewsItems = [];

// сформируем из массива viewsItems новый массив newViewsItems только из тех данных, timestamp которых не более 30 дней
for (var i = 0, length = viewsItems.length; i < length; i++) {
  if (viewsItems.timestamp > (Date.now() - 1000 * 60 * 60 * 24 * 30)) {
    newViewsItems.push(viewsItems);
  }
}

// например, если текущая дата 11.04.2020, то в массив newViewsItems попадут все элементы, кроме первого

// сохраним новый массив, очищенный от старых записей в LocalStorage
localStorage.setItem('viewsItems', JSON.stringify(newViewsItems));

sessionStorage

The object is used much less often than .

Properties and methods are the same, but it’s much more limited:

  • The exists only within the current browser tab.
    • Another tab with the same page will have a different storage.
    • But it is shared between iframes in the same tab (assuming they come from the same origin).
  • The data survives page refresh, but not closing/opening the tab.

Let’s see that in action.

Run this code…

…Then refresh the page. Now you can still get the data:

…But if you open the same page in another tab, and try again there, the code above returns , meaning “nothing found”.

That’s exactly because is bound not only to the origin, but also to the browser tab. For that reason, is used sparingly.

浏览器兼容性

Update compatibility data on GitHub

Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Firefox for Android Opera for Android Safari on iOS Samsung Internet
Chrome Full support 4 Edge Full support 12 Firefox Full support 3.5 IE Full support 8 Opera Full support 10.5 Safari Full support 4 WebView Android Full support ≤37 Chrome Android Full support 18 Firefox Android Full support 6 Opera Android Full support 11 Safari iOS Full support 3.2 Samsung Internet Android Full support 1.0
Chrome Full support 4 Edge Full support 12 Firefox Full support 3.5 IE Full support 8 Opera Full support 10.5 Safari Full support 4 WebView Android Full support Yes Chrome Android Full support 18 Firefox Android Full support 6 Opera Android Full support 11 Safari iOS Full support 3.2 Samsung Internet Android Full support 1.0
Chrome Full support 4 Edge Full support 12 Firefox Full support 3.5 IE Full support 8 Opera Full support 10.5 Safari Full support 4 WebView Android Full support ≤37 Chrome Android Full support 18 Firefox Android Full support 6 Opera Android Full support 11 Safari iOS Full support 3.2 Samsung Internet Android Full support 1.0
Chrome Full support 4 Edge Full support 12 Firefox Full support 3.5 IE Full support 8 Opera Full support 10.5 Safari Full support 4 WebView Android Full support Yes Chrome Android Full support 18 Firefox Android Full support 6 Opera Android Full support 11 Safari iOS Full support 3.2 Samsung Internet Android Full support 1.0
Chrome Full support 4 Edge Full support 12 Firefox Full support 3.5 IE Full support 8 Opera Full support 10.5 Safari Full support 4 WebView Android Full support Yes Chrome Android Full support 18 Firefox Android Full support 6 Opera Android Full support 11 Safari iOS Full support 3.2 Samsung Internet Android Full support 1.0
Chrome Full support 4 Edge Full support 12 Firefox Full support 3.5 IE Full support 8 Opera Full support 10.5 Safari Full support 4 WebView Android Full support ≤37 Chrome Android Full support 18 Firefox Android Full support 6 Opera Android Full support 11 Safari iOS Full support 3.2 Samsung Internet Android Full support 1.0
Chrome Full support 4 Edge Full support 12 Firefox Full support 3.5 IE Full support 8 Opera Full support 10.5 Safari Full support 4 WebView Android Full support ≤37 Chrome Android Full support 18 Firefox Android Full support 6 Opera Android Full support 11 Safari iOS Full support 3.2 Samsung Internet Android Full support 1.0

Storage event

When the data gets updated in or , event triggers, with properties:

  • – the key that was changed ( if is called).
  • – the old value ( if the key is newly added).
  • – the new value ( if the key is removed).
  • – the url of the document where the update happened.
  • – either or object where the update happened.

The important thing is: the event triggers on all objects where the storage is accessible, except the one that caused it.

Let’s elaborate.

Imagine, you have two windows with the same site in each. So is shared between them.

You might want to open this page in two browser windows to test the code below.

If both windows are listening for , then each one will react on updates that happened in the other one.

Please note that the event also contains: – the url of the document where the data was updated.

Also, contains the storage object – the event is the same for both and , so references the one that was modified. We may even want to set something back in it, to “respond” to a change.

That allows different windows from the same origin to exchange messages.

Modern browsers also support Broadcast channel API, the special API for same-origin inter-window communication, it’s more full featured, but less supported. There are libraries that polyfill that API, based on , that make it available everywhere.


С этим читают