Бързо, но пълно ръководство за IndexedDB и съхраняване на данни в браузърите

Интересувате ли се от изучаването на JavaScript? Вземете моята електронна книга на JavaScript на jshandbook.com

Въведение в IndexedDB

IndexedDB е една от възможностите за съхранение, въведени в браузърите през годините.

Това е хранилище на ключ / стойност (база данни noSQL), считано за окончателното решение за съхранение на данни в браузърите .

Това е асинхронен API, което означава, че извършването на скъпи операции няма да блокира нишката на потребителския интерфейс, предоставяйки небрежно изживяване на потребителите. Той може да съхранява неопределено количество данни, въпреки че веднъж над определен праг потребителят е подканен да даде на сайта по-високи ограничения.

Поддържа се във всички съвременни браузъри.

Той поддържа транзакции, създаване на версии и дава добра производителност.

В браузъра също можем да използваме:

  • Бисквитките : могат да хостват много малко количество низове
  • Уеб съхранение (или DOM съхранение), термин, който обикновено идентифицира localStorage и sessionStorage, две хранилища ключ / стойност. sessionStorage, не задържа данни, които се изчистват, когато сесията приключи, докато localStorage запазва данните през сесиите

Локалното / сесийно съхранение има недостатъка, че се ограничава до малък (и несъвместим) размер, като внедряването на браузъри предлага от 2MB до 10MB пространство на сайт.

В миналото имахме и Web SQL , обвивка около SQLite, но сега това е оттеглено и не се поддържа в някои съвременни браузъри, никога не е бил признат стандарт и затова не трябва да се използва, въпреки че 83% от потребителите имат тази технология на своите устройства според Мога ли да използвам.

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

Базата данни е частна за даден домейн , така че всеки друг сайт няма достъп до друг уебсайт, който IndexedDB съхранява.

Всеки магазин обикновено съдържа набор от неща , които могат да бъдат

  • струни
  • числа
  • обекти
  • масиви
  • дати

Например може да имате магазин, който съдържа публикации, друг, който съдържа коментари.

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

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

От появата на Promises в ES6 и последвалия ход на API за използване на обещания, IndexedDB API изглежда малко старо училище .

Въпреки че няма нищо лошо в него, във всички примери, които ще обясня, ще използвам обещаната библиотека IndexedDB от Jake Archibald, която е мъничък слой върху API на IndexedDB, за да улесни използването.

Тази библиотека се използва и за всички примери на уебсайта на Google Developers по отношение на IndexedDB

Създайте база данни IndexedDB

Най-простият начин е да използвате unpkg , като добавите това към заглавката на страницата:

 import { openDB, deleteDB } from '//unpkg.com/idb?module'  

Преди да използвате API на IndexedDB, винаги се уверете, че проверявате за поддръжка в браузъра, въпреки че е широко достъпен, никога не знаете кой браузър използва потребителят:

(() => { 'use strict' if (!('indexedDB' in window)) { console.warn('IndexedDB not supported') return } //...IndexedDB code })() 

Как да създам база данни

Използване openDB():

(async () => { //... const dbName = 'mydbname' const storeName = 'store1' const version = 1 //versions start at 1 const db = await openDB(dbName, version, { upgrade(db, oldVersion, newVersion, transaction) { const store = db.createObjectStore(storeName) } }) })() 

Първите 2 параметъра са името на базата данни и версията. Третият параметър, който не е задължителен, е обект, който съдържа функция, извикана само ако номерът на версията е по-висок от текущата инсталирана версия на базата данни . В тялото на функцията можете да надстроите структурата (хранилища и индекси) на db.

Добавяне на данни в магазин

Добавяне на данни при създаване на хранилището, инициализиране

Използвате putметода на хранилището на обекти, но първо се нуждаем от препратка към него, което можем да получим, db.createObjectStore()когато го създадем.

Когато се използва put, стойността е първият аргумент, ключът е вторият. Това е така, защото ако посочите keyPathпри създаването на хранилището на обекти, не е необходимо да въвеждате името на ключа при всяка заявка put (), можете просто да напишете стойността.

Това се попълва store0веднага щом го създадем:

(async () => { //... const dbName = 'mydbname' const storeName = 'store0' const version = 1 const db = await openDB(dbName, version,{ upgrade(db, oldVersion, newVersion, transaction) { const store = db.createObjectStore(storeName) store.put('Hello world!', 'Hello') } }) })() 

Добавяне на данни, когато магазинът вече е създаден, като се използват транзакции

За да добавите елементи по-късно по пътя, трябва да създадете транзакция за четене / запис , която гарантира целостта на базата данни (ако операцията се провали, всички операции в транзакцията се връщат назад и състоянието се връща в известно състояние).

За това използвайте препратка към dbPromiseобекта, който получихме при извикване openDB, и изпълнете:

(async () => { //... const dbName = 'mydbname' const storeName = 'store0' const version = 1 const db = await openDB(/* ... */) const tx = db.transaction(storeName, 'readwrite') const store = await tx.objectStore(storeName) const val = 'hey!' const key = 'Hello again' const value = await store.put(val, key) await tx.done })() 

Получаване на данни от магазин

Получаване на един артикул от магазин: get()

const key = 'Hello again' const item = await db.transaction(storeName).objectStore(storeName).get(key) 

Изтегляне на всички артикули от магазин: getAll()

Вземете всички съхранени ключове

const items = await db.transaction(storeName).objectStore(storeName).getAllKeys() 

Вземете всички запазени стойности

const items = await db.transaction(storeName).objectStore(storeName).getAll() 

Изтриване на данни от IndexedDB

Изтриване на базата данни, хранилище на обекти и данни

Изтрийте цяла база данни IndexedDB

const dbName = 'mydbname' await deleteDB(dbName) 

За изтриване на данни в обект за съхранение

Използваме транзакция:

(async () => { //... const dbName = 'mydbname' const storeName = 'store1' const version = 1 const db = await openDB(dbName, version, { upgrade(db, oldVersion, newVersion, transaction) { const store = db.createObjectStore(storeName) } }) const tx = await db.transaction(storeName, 'readwrite') const store = await tx.objectStore(storeName) const key = 'Hello again' await store.delete(key) await tx.done })() 

Мигрирайте от предишната версия на база данни

The third (optional) parameter of the openDB() function is an object that can contain an upgrade function called only if the version number is higher than the current installed database version. In that function body you can upgrade the structure (stores and indexes) of the db:

const name = 'mydbname' const version = 1 openDB(name, version, { upgrade(db, oldVersion, newVersion, transaction) { console.log(oldVersion) } }) 

In this callback, you can check from which version the user is updating, and perform some operations accordingly.

You can perform a migration from a previous database version using this syntax

(async () => { //... const dbName = 'mydbname' const storeName = 'store0' const version = 1 const db = await openDB(dbName, version, { upgrade(db, oldVersion, newVersion, transaction) { switch (oldVersion) { case 0: // no db created before // a store introduced in version 1 db.createObjectStore('store1') case 1: // a new store in version 2 db.createObjectStore('store2', { keyPath: 'name' }) } db.createObjectStore(storeName) } }) })() 

Unique keys

createObjectStore() as you can see in case 1 accepts a second parameter that indicates the index key of the database. This is very useful when you store objects: put() calls don't need a second parameter, but can just take the value (an object) and the key will be mapped to the object property that has that name.

The index gives you a way to retrieve a value later by that specific key, and it must be unique (every item must have a different key)

A key can be set to auto increment, so you don't need to keep track of it on the client code:

db.createObjectStore('notes', { autoIncrement: true }) 

Use auto increment if your values do not contain a unique key already (for example, if you collect email addresses without an associated name).

Check if a store exists

You can check if an object store already exists by calling the objectStoreNames() method:

const storeName = 'store1' if (!db.objectStoreNames.contains(storeName)) { db.createObjectStore(storeName) } 

Deleting from IndexedDB

Deleting the database, an object store and data

Delete a database

await deleteDB('mydb') 

Delete an object store

An object store can only be deleted in the callback when opening a db, and that callback is only called if you specify a version higher than the one currently installed:

const db = await openDB('dogsdb', 2, { upgrade(db, oldVersion, newVersion, transaction) { switch (oldVersion) { case 0: // no db created before // a store introduced in version 1 db.createObjectStore('store1') case 1: // delete the old store in version 2, create a new one db.deleteObjectStore('store1') db.createObjectStore('store2') } } }) 

To delete data in an object store use a transaction

const key = 232 //a random key const db = await openDB(/*...*/) const tx = await db.transaction('store', 'readwrite') const store = await tx.objectStore('store') await store.delete(key) await tx.complete 

There's more!

Това са само основите. Не говорих за курсори и по-напреднали неща. Има още неща за IndexedDB, но се надявам това да ви даде предимство.

Интересувате ли се от изучаването на JavaScript? Вземете моята книга с JavaScript на jshandbook.com