En hurtig, men komplet guide til IndexedDB og lagring af data i browsere

Er du interesseret i at lære JavaScript? Få min gratis e-bog på jshandbook.com

IndexedDB er en af ​​lagringskapaciteterne introduceret i browsere gennem årene. Det er en nøgle / værdibutik (en noSQL-database), der betragtes som den endelige løsning til lagring af data i browsere.

IndexedDB er et asynkron API, hvilket betyder, at udførelse af dyre operationer ikke blokerer UI-tråden, hvilket giver en slurvende oplevelse for brugerne.

Det kan gemme en ubestemt mængde data, skønt brugeren en gang over en bestemt tærskel bliver bedt om at give webstedet højere grænser.

Det understøttes på alle moderne browsere.

Det understøtter transaktioner og versionering og giver god ydelse.

Inde i browseren kan vi også bruge:

  • Cookies, der kan rumme en meget lille mængde strenge
  • DOM Storage (eller Web Storage), et udtryk, der ofte identificerer localStorage og sessionStorage, to nøgle / værdibutikker. sessionStorage, opbevarer ikke data, som ryddes, når sessionen slutter, mens localStorage opbevarer dataene på tværs af sessioner

Lokal / session lagring har ulempen ved at blive afkortet i en lille (og inkonsekvent) størrelse, med browsernes implementering tilbud fra 2MB til 10MB plads pr. Websted.

Tidligere havde vi også Web SQL, en indpakning omkring SQLite. Men dette udskrives nu og understøttes ikke på nogle moderne browsere. Det har aldrig været en anerkendt standard, og derfor bør den ikke bruges - selvom 83% af brugerne har denne teknologi på deres enheder i henhold til Can I Use.

Mens du teknisk set kan oprette flere databaser pr. Websted, opretter du normalt en enkelt database. Inde i databasen kan du oprette flere objektlagre.

En database er privat for et domæne, så ethvert andet sted kan ikke få adgang til et andet websteds IndexedDB-butikker.

Hver butik indeholder normalt et sæt ting, der kan være:

  • strygere
  • numre
  • objekter
  • arrays
  • datoer

For eksempel har du muligvis en butik, der indeholder indlæg, og en anden, der indeholder kommentarer.

En butik indeholder et antal elementer, der har en unik nøgle, der repræsenterer den måde, hvorpå et objekt kan identificeres.

Du kan ændre disse butikker ved hjælp af transaktioner, ved at udføre tilføjelse, redigering og sletning af handlinger og ved at iterere over de elementer, de indeholder.

Siden fremkomsten af ​​løfter i ES2015 og den efterfølgende flytning af API'er til brug af løfter, virker IndexedDB API en smule gammel skole.

Selvom der ikke er noget galt med det, vil jeg i alle de eksempler, jeg forklarer, bruge IndexedDB Promised Library af Jake Archibald, som er et lille lag øverst på IndexedDB API for at gøre det lettere at bruge.

Dette bibliotek bruges også til alle eksemplerne på Google Developers websted vedrørende IndexedDB.

Opret en indekseret DB-database

Inkluder idb lib ved hjælp af:

garn tilføj idb

Og inkluder det derefter på din side, enten ved hjælp af Webpack eller Browserify eller et hvilket som helst andet build-system, eller blot:

Og vi er klar til at gå.

Før du bruger IndexedDB API, skal du altid sørge for at tjekke for support i browseren, selvom den er bredt tilgængelig. Du ved aldrig, hvilken browser brugeren bruger:

(() => {
  'brug streng'
  hvis (! ('indekseret DB' i vindue)) {
    console.warn ('IndexedDB understøttes ikke')
    Vend tilbage
  }
//...IndexedDB-kode
}) ()

Sådan opretter du en database

Brug af idb.open ():

const name = 'mydbname'
const version = 1 // versioner starter ved 1
idb.open (navn, version, upgradeDb => {})

De to første parametre er selvforklarende. Den tredje parameter, der er valgfri, er et tilbagekald, der kun kaldes, hvis versionnummeret er højere end den nuværende installerede databaseversion. I callback-funktionskroppen kan du opgradere strukturen (lagre og indekser) for db.

Vi bruger navnet upgradeDB til tilbagekaldet til at identificere, at det er tid til at opdatere databasen, hvis det er nødvendigt.

Opret en Object Store

Sådan opretter du en objektlager eller tilføjer en ny

En objektlager oprettes eller opdateres i denne tilbagekald ved hjælp af syntaks db.createObjectStore ('butiksnavn', indstillinger):

const dbPromise = idb.open ('mydb', 1, (upgradeDB) => {
  upgradeDB.createObjectStore (store1 ')
})
.then (db => console.log ('succes'))

Hvis du installerede en tidligere version, giver tilbagekaldet dig mulighed for at udføre migreringen:

const dbPromise = idb.open ('keyval-store', 3, (upgradeDB) => {
  switch (upgradeDB.oldVersion) {
    sag 0: // ingen db oprettet før
      // en butik introduceret i version 1
      upgradeDB.createObjectStore (store1 ')
    sag 1:
      // en ny butik i version 2
      upgradeDB.createObjectStore ('store2', {keyPath: 'name'})
  }
})
.then (db => console.log ('succes'))

createObjectStore (), som du kan se i tilfælde 1 accepterer en anden parameter, der angiver databasens indeksnøgle. Dette er meget nyttigt, når du gemmer objekter: opkald () () -opkald behøver ikke en anden parameter, men kan bare tage værdien (et objekt), og nøglen kortlægges til den objektejendom, der har det navn.

Indekset giver dig en måde at hente en værdi senere ved den specifikke nøgle, og den skal være unik (hvert element skal have en anden nøgle).

En nøgle kan indstilles til automatisk forøgelse, så du ikke behøver at holde styr på den på klientkoden. Hvis du ikke angiver en nøgle, opretter IndexedDB den gennemsigtigt for os:

upgradeDb.createObjectStore ('noter', {autoIncrement: true})

men du kan også angive et specifikt felt med objektværdi til automatisk inkrement:

upgradeDb.createObjectStore ('noter', {
  keyPath: 'id',
  autoIncrement: sandt
})

Brug som regel en generel regel, hvis dine værdier ikke allerede indeholder en unik nøgle (f.eks. En e-mail-adresse til brugere).

Indekser

Et indeks er en måde at hente data fra objektlageret på. Det er defineret sammen med oprettelsen af ​​databasen i idb.open () tilbagekald på denne måde:

const dbPromise = idb.open ('dogdb', 1, (upgradeDB) => {
  const dogs = upgradeDB.createObjectStore ('hunde')
  dogs.createIndex ('navn', 'navn', {unikt: falskt})
})

Den unikke mulighed bestemmer, om indeksværdien skal være unik, og ingen duplikatværdier må tilføjes.

Du kan få adgang til et objektlager, der allerede er oprettet ved hjælp af metoden upgradeDb.transaction.objectStore ():

const dbPromise = idb.open ('dogdb', 1, (upgradeDB) => {
  const dogs = upgradeDB.transaction.objectStore ('hunde')
  dogs.createIndex ('navn', 'navn', {unikt: falskt})
})

Kontroller, om der findes en butik

Du kan kontrollere, om der allerede findes en objektlager ved at kalde metoden objectStoreNames ():

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

Sletning fra IndexedDB

Slet en database

idb.delete ('mydb'). derefter (() => console.log ('gjort'))

Slet et objektlager

En objektlager kan kun slettes i tilbagekaldet, når du åbner en db, og den tilbagekald kaldes kun, hvis du angiver en version, der er højere end den, der i øjeblikket er installeret:

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

For at slette data i en objektlager skal du bruge denne transaktion:

const-tast = 232
dbPromise.then ((db) => {
  const tx = db.transaction ('store', 'readwrite')
  const store = tx.objectStore ('store')
  store.delete (nøgle)
  returner tx.complete
})
.then (() => {
  console.log ('Varen er slettet')
})

Føj en vare til databasen

Du kan bruge put-metoden i objektlageret, men først har vi brug for en henvisning til den, som vi kan få fra upgradeDB.createObjectStore (), når vi opretter den.

Når man bruger put, er værdien det første argument, og nøglen er det andet. Dette skyldes, at hvis du specificerer keyPath, når du opretter en objektlager, behøver du ikke at indtaste nøglenavnet på hver anmodning om put (). Du kan bare skrive værdien.

Dette udfylder store0, så snart vi opretter det:

idb.open ('mydb', 1, (upgradeDB) => {
  keyValStore = upgradeDB.createObjectStore ('store0')
  keyValStore.put ('Hej verden!', 'Hej')
})

For at tilføje varer senere på vejen skal du oprette en transaktion. Det sikrer databasens integritet (hvis en operation mislykkes, rulles alle operationerne i transaktionen tilbage, og staten vender tilbage til en kendt tilstand).

Til det skal du bruge en henvisning til dbPromise-objektet, vi fik, når vi kalder idb.open (), og kør:

dbPromise.then ((db) => {
  const val = 'hey!'
  const key = 'Hej igen'
  const tx = db.transaction ('store1', 'readwrite')
  tx.objectStore ('store1'). put (val, nøgle)
  returner tx.complete
})
.then (() => {
  console.log ('Transaktion afsluttet')
})
.fang (() => {
  console.log ('Transaktion mislykkedes')
})

IndexedDB API tilbyder også metoden (), men da put () giver os mulighed for både at tilføje og opdatere, er det enklere at bare bruge den.

Henter varer fra en butik

Henter en bestemt vare fra en butik ved hjælp af get ()

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

Henter alle elementerne ved hjælp af getAll ()

dbPromise.then (db => db.transaction ('store1')
                       .objectStore (store1 ')
                       .getAll ())
.then (objekter => konsol.log (objekter))

Itererer om alle elementerne ved hjælp af en markør via openCursor ()

dbPromise.then ((db) => {
  const tx = db.transaction ('store', 'readonly')
  const store = tx.objectStore ('store')
  return store.openCursor ()
})
.then (funktionslogItems (cursor) {
  hvis (! markør) {return}
  console.log ('cursor er på:', cursor.key)
  for (const-felt i cursor.value) {
    console.log (cursor.value [felt])
  }
  return cursor.continue (). derefter (logItems)
})
.then (() => {
  console.log ( 'færdig!')
})

Itererer om en undergruppe af elementerne ved hjælp af grænser og markører

const searchItems = (nedre, øvre) => {
  if (lavere === '' && øvre === '') {return}
  lad rækkevidde
  if (nederste! == '' && øvre! == '') {
    rækkevidde = IDBKeyRange.bound (nederste, øvre)
  } andet hvis (lavere === '') {
    rækkevidde = IDBKeyRange.upperBound (øvre)
  } andet {
    rækkevidde = IDBKeyRange.lowerBound (lavere)
  }
  dbPromise.then ((db) => {
    const tx = db.transaction (['hunde'], 'readonly')
    const store = tx.objectStore ('hunde')
    const index = store.index ('alder')
    return index.openCursor (rækkevidde)
  })
  .then (funktion showRange (cursor) {
    hvis (! markør) {return}
    console.log ('cursor er på:', cursor.key)
    for (const-felt i cursor.value) {
      console.log (cursor.value [felt])
    }
    returner cursor.continue (). derefter (showRange)
  })
  .then (() => {
    console.log ( 'færdig!')
  })
}
searchDogsBetween Aldere (3, 10)
Er du interesseret i at lære JavaScript? Få min gratis e-bog på jshandbook.com