## Хранение данных в браузере (кэш браузера): Cookie, LocalStorage, SessionStorage, IndexDB


## Есть куки. Зачем тогда Web storage API?

* В отличие от куки, объекты веб-хранилища не отправляются на сервер при каждом запросе. 
Поэтому мы можем хранить больше данных. Браузеры могут выделить +-5 мегабайтов данных;
* Ещё одно отличие от куки – сервер не может манипулировать объектами хранилища через HTTP-заголовки. Всё делается при помощи JavaScript;
* Хранилище привязано к источнику (домен/протокол/порт). Это значит, что разные протоколы или поддомены определяют разные объекты хранилища, и они не могут получить доступ к данным друг друга.

В качестве хранилищ данных на стороне пользователя вместо них можно использовать [Web storage API](https://developer.mozilla.org/ru/docs/Web/API/Web_Storage_API) (localStorage и sessionStorage) и [IndexedDB](https://developer.mozilla.org/ru/docs/Web/API/IndexedDB_API).

## Сравнение

| Характеристика | Cookie | LocalStorage | SessionStorage |
|----------------|--------|--------------|----------------|
| **Место хранения** | Браузер, автоматически отправляются на сервер | Только браузер, на сервер не отправляются | Только браузер, на сервер не отправляются |
| **Управление** | Сервер (Set-Cookie) и web-клиент (document.cookie) | Только web-клиент (JavaScript API) | Только web-клиент (JavaScript API) |
| **Объём** | До 4 КБ | До 5–10 МБ (зависит от браузера) | До 5–10 МБ (зависит от браузера) |
| **Срок жизни** | По умолчанию сессионные (до закрытия браузера), можно установить Expires или Max-Age | Бессрочный (до явного удаления через JS или очистки данных браузера) | До закрытия вкладки/окна (при восстановлении не сохраняются) |
| **Доступность между вкладками/окнами** | Доступны из любого окна/вкладки одного источника (если нет флага HttpOnly) | Доступны из любого окна/вкладки одного источника (общие для всех) | Доступны только в рамках одной вкладки (у каждой вкладки своя копия) |


### LocalStorage:

![LocalStorageInApplication](/pictures/ComputerScience/Web/LocalStorageInApplication.png)

Смотрим хранит ли ваш браузер какие-то LocalStorage с этого сайта:

`alert( JSON.stringify(localStorage) );` или `console.table(localStorage);`

```js
// записываем переменную nameStorage
const name = 'Mario Dev';
localStorage setItem('nameStorage', JSON.stringify(name));
// достаем переменную nameStorage
const getName = localStorage.getItem('nameStorage');
console.log(getName) ;
```

### SessionStorage:

![SessionStorageInApplication](/pictures/ComputerScience/Web/SessionStorageInApplication.png)

Смотрим хранит ли ваш браузер какие-то SessionStorage с этого сайта:

`alert( JSON.stringify(sessionStorage) );` или `console.table(sessionStorage);`

```js
// записываем переменную nameStorage
const name = 'Mario Dev';
sessionStorage setItem('nameStorage', JSON.stringify(name));
// достаем переменную nameStorage
const getName = sessionStorage.getItem('nameStorage');
console.log(getName) ;
```

### Как сохранять не только string?

```js
const person = [
{ id: 1, name: 'Mario Dev', isWork: true },
{ id: 2, name: 'Egor', isWork: false }
];

localStorage setItem('nameStorage', JSON.stringify(name));
const getPersons = localStorage getItem( 'personData');
// выводим string
console.log(getPersons);
// выводим сам JSON объект
console.log(JSON.parse(getPersons))
```

### Событие storage

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

* key – ключ, который обновился (null, если вызван .clear());
* oldValue – старое значение (null, если ключ добавлен впервые);
* newValue – новое значение (null, если ключ был удалён);
* url – url документа, где произошло обновление;
* storageArea – объект localStorage или sessionStorage, где произошло обновление.

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

Это необходимо для **уведомления** других вкладки, что что-то поменялось. Иначе нам пришлось бы ходить каждые 5 минут запрашивать данные и сравнивать со старым изменилось ли оно.

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

localStorage.setItem('now', Date.now());
```

Браузеры поддерживают [Broadcast channel API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API) специальный API для связи между окнами одного источника, он более полнофункциональный, но менее поддерживаемый. Существуют библиотеки (полифилы), которые эмулируют это API на основе localStorage и делают его доступным везде.

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

Когда пользователь закроет страницу и потом откроет её заново он должен увидеть последнее введённое значение.

Вот пример:

![LocalStorageInApplication](/pictures/ComputerScience/Web/StorageExample.png)

Песочница для задачи: [ссылка](https://plnkr.co/edit/Vwq7Cl0WcCCT0Vdp?p=preview&preview)

---

[2.3.2.8 Cookie Theme](./2.3.2.8%20Cookie.md) | [Back To iTWiki Contents](https://github.com/eldaroid/iTWiki) | [2.4 Architecture Theme Folder](/2%20ComputerScience/2.4%20Architecture/)
