En hurtig, men komplet guide til IndexedDB og lagring af data i browsere
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 put
metoden 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 put
er værdien det første argument, nøglen er det andet. Dette skyldes, at hvis du angiver, keyPath
når du opretter objektbutikken, behøver du ikke indtaste nøglenavnet på hver put () anmodning, du kan bare skrive værdien.
Dette udfyldes, store0
så 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 dbPromise
objekt, 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