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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

След появата на Promises в ES2015 и последващото преминаване на API към използване на обещания, API IndexedDB изглежда малко стара школа.

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

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

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

Включете lib lib, като използвате:

прежда добавете idb

И след това го включете във вашата страница, или използвайки Webpack или Browserify или друга система за изграждане, или просто:

И ние сме готови да тръгнем

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

(() => {
  "използвайте стриктно"
  if (! ('indexedDB' in window)) {
    console.warn ('IndexedDB не се поддържа')
    връщане
  }
//...IndexedDB код
}) ()

Как да създадете база данни

Използване на idb.open ():

const name = 'mydbname'
const версия = 1 // версиите започват от 1
idb.open (име, версия, надстройкаDb => {})

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

Използваме името upgradeDB за обратния разговор, за да идентифицираме, че това е моментът за актуализиране на базата данни, ако е необходимо.

Създайте магазин за обекти

Как да създадете магазин за обекти или да добавите нов

В този обратен ред се създава или актуализира магазин за обекти, използвайки синтаксиса db.createObjectStore ('storeName', опции):

const dbPromise = idb.open ('mydb', 1, (upgradeDB) => {
  upgradeDB.createObjectStore ( "store1)
})
.then (db => console.log ('успех'))

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

const dbPromise = idb.open ('keyval-store', 3, (upgradeDB) => {
  превключвател (upgradeDB.oldVersion) {
    случай 0: // няма db създаден преди
      // магазин, представен във версия 1
      upgradeDB.createObjectStore ( "store1)
    случай 1:
      // нов магазин във версия 2
      upgradeDB.createObjectStore ('store2', {keyPath: 'name'})
  }
})
.then (db => console.log ('успех'))

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

Индексът ви дава начин да извлечете стойност по-късно чрез този конкретен ключ и той трябва да бъде уникален (всеки елемент трябва да има различен ключ).

Ключ може да бъде зададен за автоматично увеличение, така че не е необходимо да го следите в клиентския код. Ако не посочите ключ, IndexedDB ще го създаде прозрачно за нас:

upgradeDb.createObjectStore ('бележки', {autoIncrement: true})

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

upgradeDb.createObjectStore ('бележки', {
  keyPath: 'id',
  autoIncrement: вярно
})

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

Индекси

Индексът е начин за извличане на данни от магазина на обекти. Тя се дефинира заедно със създаването на базата данни в обратния разговор idb.open () по този начин:

const dbPromise = idb.open ('dogdb', 1, (надстройкаDB) => {
  const dog = upgradeDB.createObjectStore ('кучета')
  dog.createIndex ('име', 'име', {уникален: невярно})
})

Уникалната опция определя дали стойността на индекса трябва да бъде уникална и не се допуска добавяне на дублиращи се стойности.

Можете да получите достъп до обект магазин, вече създаден с помощта на метода upgradeDb.transaction.objectStore ():

const dbPromise = idb.open ('dogdb', 1, (upgradeDB) => {
  const dog = upgradeDB.transaction.objectStore ('кучета')
  dog.createIndex ('име', 'име', {уникален: невярно})
})

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

Можете да проверите дали магазин за обекти вече съществува, като се обадите на метода objectStoreNames ():

if (! upgradeDb.objectStoreNames.contains ('store3')) {
  upgradeDb.createObjectStore ( "store3)
}

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

Изтрийте база данни

idb.delete ('mydb'). тогава (() => console.log ('свършено'))

Изтрийте магазин за обекти

Магазинът на обектите може да бъде изтрит в обратния разговор само при отваряне на db и този обратно повикване се извиква само ако посочите версия, по-висока от тази, която е инсталирана в момента:

const dbPromise = idb.open ('dogdb', 2, (upgradeDB) => {
  upgradeDB.deleteObjectStore ( "old_store)
})

За да изтриете данни в магазин на обекти, използвайте тази транзакция:

const ключ = 232
dbPromise.then ((db) => {
  const tx = db.transaction ('магазин', 'readwrite')
  const store = tx.objectStore ('магазин')
  store.delete (ключ)
  върнете tx.complete
})
.then (() => {
  console.log („Елементът е изтрит“)
})

Добавете елемент в базата данни

Можете да използвате метода на пускане на обектния магазин, но първо се нуждаем от препратка към него, която можем да получим от upgradeDB.createObjectStore (), когато го създаваме.

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

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

idb.open ('mydb', 1, (upgradeDB) => {
  keyValStore = upgradeDB.createObjectStore ('store0')
  keyValStore.put ('Здравей свят!', 'Здравей')
})

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

За това използвайте препратка към обекта dbPromise, който получихме при извикване на idb.open (), и стартирайте:

dbPromise.then ((db) => {
  const val = 'ей!'
  const key = 'Здравейте отново'
  const tx = db.transaction ('store1', 'readwrite')
  tx.objectStore ('store1'). put (val, ключ)
  върнете tx.complete
})
.then (() => {
  console.log („Сделката приключи“)
})
.catch (() => {
  console.log ('Транзакция не е успешна')
})

API на IndexedDB също предлага метода add (), но тъй като put () ни позволява да добавяме и актуализираме, по-просто е просто да го използваме.

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

Получаване на конкретен артикул от магазин с помощта на get ()

dbPromise.then (db => db.transaction ('objs'))
                       .objectStore ( "objs)
                       .get (123456))
.then (obj => console.log (obj))

Извличане на всички елементи с помощта на getAll ()

dbPromise.then (db => db.transaction ('store1'))
                       .objectStore ( "store1)
                       .Вземи всичко())
.then (обекти => console.log (обекти))

Итерация на всички елементи с помощта на курсор чрез openCursor ()

dbPromise.then ((db) => {
  const tx = db.transaction ('магазин', 'само за четене')
  const store = tx.objectStore ('магазин')
  връщане store.openCursor ()
})
.then (функция logItems (курсор) {
  ако (! курсор) {return}
  console.log ('курсорът е в:', cursor.key)
  за (поле const в cursor.value) {
    console.log (cursor.value [поле])
  }
  върнете cursor.continue (). тогава (logItems)
})
.then (() => {
  console.log ( "Браво!")
})

Итерация на подмножество от елементи с помощта на граници и курсори

const searchItems = (долна, горна) => {
  ако (долен === '' && горен === '') {return}
  нека обхват
  ако (долна! == '' && горна! == '') {
    обхват = IDBKeyRange.bound (долен, горен)
  } else if (по-нисък === '') {
    обхват = IDBKeyRange.upperBound (горен)
  } else {
    обхват = IDBKeyRange.lowerBound (по-нисък)
  }
  dbPromise.then ((db) => {
    const tx = db.transaction (['кучета'], 'само за четене')
    const store = tx.objectStore ('кучета')
    const index = store.index ('age')
    връщане index.openCursor (обхват)
  })
  .then (функция showRange (курсор) {
    ако (! курсор) {return}
    console.log ('курсорът е в:', cursor.key)
    за (поле const в cursor.value) {
      console.log (cursor.value [поле])
    }
    върнете cursor.continue (). тогава (showRange)
  })
  .then (() => {
    console.log ( "Браво!")
  })
}
търсенеКучества между възрасти (3, 10)
Искате да научите JavaScript? Вземете безплатната ми електронна книга на jshandbook.com