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

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

Introduktion til IndexedDB

IndexedDB er en af ​​de lagringsfunktioner, der er introduceret i browsere gennem årene.

Det er en nøgle- / værdilager (en noSQL-database), der anses for at være den endelige løsning til lagring af data i browsere .

Det er en asynkron API, hvilket betyder, at udførelse af dyre operationer ikke vil blokere UI-tråden, hvilket giver brugerne en sjusket oplevelse. Det kan gemme en ubestemt mængde data, selvom brugeren en gang over en bestemt tærskel bliver bedt om at give webstedet højere grænser.

Det understøttes i alle moderne browsere.

Det understøtter transaktioner, versionering og giver god ydeevne.

Inde i browseren kan vi også bruge:

  • Cookies : kan være vært for en meget lille mængde strenge
  • Web Opbevaring (eller DOM Storage), et begreb, der ofte identificerer localStorage og sessionStorage, to nøgle / værdi-butikker. sessionStorage, gemmer ikke data, som ryddes, når sessionen slutter, mens localStorage opbevarer data på tværs af sessioner

Lokal / session-lagring har den ulempe, at de er begrænset i en lille (og inkonsekvent) størrelse, med implementering af browsere, der tilbyder fra 2 MB til 10 MB plads pr. Sted.

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

Mens du teknisk kan oprette flere databaser pr. Websted, opretter du generelt en enkelt database , og inde i den database kan du oprette flere objektbutikker .

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

Hver butik indeholder normalt et sæt ting , som det kan være

  • strenge
  • numre
  • genstande
  • arrays
  • datoer

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

En butik indeholder et antal varer, 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øj, redigere og slette operationer og gentage de varer, de indeholder.

Siden fremkomsten af ​​løfter i ES6 og den efterfølgende flytning af API'er til brug af løfter virker IndexedDB API lidt gammel skole .

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

Dette bibliotek bruges også til alle eksemplerne på Google Developers-webstedet vedrørende IndexedDB

Opret en IndexedDB-database

Den enkleste måde er at bruge unpkg ved at føje dette til sidehovedet:

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

Før du bruger IndexedDB API, skal du altid kontrollere, om der er support i browseren, selvom den er bredt tilgængelig, ved du aldrig, hvilken browser brugeren bruger:

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

Sådan oprettes en database

Brug af 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) } }) })() 

De første 2 parametre er databasens navn og verson. Den tredje param, som er valgfri, er et objekt, der kun indeholder en funktion, der kaldes, hvis versionsnummeret er højere end den nuværende installerede databaseversion . I funktionskroppen kan du opgradere strukturen (lagre og indekser) af db.

Tilføjelse af data i en butik

Tilføjelse af data, når butikken oprettes, initialisering

Du bruger putmetoden til objektbutikken, men først har vi brug for en henvisning til den, som vi kan få fra, db.createObjectStore()når vi opretter den.

Ved brug puter værdien det første argument, nøglen er det andet. Dette skyldes, at hvis du angiver, keyPathnår du opretter objektbutikken, behøver du ikke indtaste nøglenavnet på hver put () anmodning, du kan bare skrive værdien.

Dette udfyldes, store0så snart vi opretter det:

(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') } }) })() 

Tilføjelse af data, når butikken allerede er oprettet ved hjælp af transaktioner

For at tilføje elementer senere på vejen skal du oprette en læse / skrive- transaktion , der sikrer databaseintegritet (hvis en operation mislykkes, rulles alle operationerne i transaktionen tilbage, og staten går tilbage til en kendt tilstand).

Brug en henvisning til det dbPromiseobjekt, vi fik, da vi ringede til det openDB, og kør:

(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 })() 

Henter data fra en butik

Få en vare fra en butik: get()

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

Henter alle varer fra en butik: getAll()

Få alle nøgler gemt

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

Få alle værdier gemt

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

Sletning af data fra IndexedDB

Sletning af databasen, et objektlager og data

Slet en hel IndexedDB-database

const dbName = 'mydbname' await deleteDB(dbName) 

Sådan slettes data i et objektlager

Vi bruger en transaktion:

(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 })() 

Migrer fra tidligere version af en database

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!

Dette er bare det grundlæggende. Jeg talte ikke om markører og mere avancerede ting. Der er mere ved IndexedDB, men jeg håber, at dette giver dig et forspring.

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