Ένας γρήγορος αλλά πλήρης οδηγός για το IndexedDB και την αποθήκευση δεδομένων σε προγράμματα περιήγησης

Ενδιαφέρεστε να μάθετε JavaScript; Αποκτήστε το ebook JavaScript στο jshandbook.com

Εισαγωγή στο IndexedDB

Το IndexedDB είναι μία από τις δυνατότητες αποθήκευσης που έχουν εισαχθεί στα προγράμματα περιήγησης με την πάροδο των ετών.

Είναι ένα κατάστημα κλειδιών / τιμών (μια βάση δεδομένων noSQL) που θεωρείται η οριστική λύση για την αποθήκευση δεδομένων σε προγράμματα περιήγησης .

Είναι ένα ασύγχρονο API, το οποίο σημαίνει ότι η εκτέλεση δαπανηρών λειτουργιών δεν θα εμποδίσει το νήμα διεπαφής χρήστη παρέχοντας μια ατημέλητη εμπειρία στους χρήστες. Μπορεί να αποθηκεύσει έναν απεριόριστο αριθμό δεδομένων, αν και μία φορά πάνω από ένα ορισμένο κατώφλι ο χρήστης ζητείται να δώσει στον ιστότοπο υψηλότερα όρια.

Υποστηρίζεται σε όλα τα σύγχρονα προγράμματα περιήγησης.

Υποστηρίζει συναλλαγές, εκδόσεις και δίνει καλή απόδοση.

Μέσα στο πρόγραμμα περιήγησης μπορούμε επίσης να χρησιμοποιήσουμε:

  • Cookies : μπορεί να φιλοξενήσει πολύ μικρό αριθμό χορδών
  • Web Storage (ή DOM Storage), ένας όρος που ταυτοποιεί συνήθως localStorage και sessionStorage, δύο καταστήματα κλειδιών / τιμών. sessionStorage, δεν διατηρεί δεδομένα, τα οποία διαγράφονται κατά τη λήξη της περιόδου σύνδεσης, ενώ το localStorage διατηρεί τα δεδομένα σε όλες τις περιόδους σύνδεσης

Ο χώρος αποθήκευσης τοπικών / συνεδριών έχει το μειονέκτημα ότι είναι περιορισμένος σε μικρό (και ασυνεπές) μέγεθος, με την εφαρμογή υλοποίησης προγραμμάτων περιήγησης από 2MB έως 10MB χώρου ανά ιστότοπο.

Στο παρελθόν είχαμε επίσης Web SQL , ένα περιτύλιγμα γύρω από το SQLite, αλλά τώρα αυτό έχει καταργηθεί και δεν υποστηρίζεται σε ορισμένα σύγχρονα προγράμματα περιήγησης, δεν ήταν ποτέ αναγνωρισμένο πρότυπο και επομένως δεν πρέπει να χρησιμοποιηθεί, αν και 83% των χρηστών έχουν αυτήν την τεχνολογία στο δικό τους συσκευές σύμφωνα με το Can I Use.

Ενώ μπορείτε τεχνικά να δημιουργήσετε πολλές βάσεις δεδομένων ανά ιστότοπο, γενικά δημιουργείτε μία μόνο βάση δεδομένων , και μέσα σε αυτήν τη βάση δεδομένων μπορείτε να δημιουργήσετε πολλά καταστήματα αντικειμένων .

Μια βάση δεδομένων είναι ιδιωτική για έναν τομέα , επομένως οποιοσδήποτε άλλος ιστότοπος δεν μπορεί να έχει πρόσβαση σε έναν άλλο ιστότοπο καταστήματα IndexedDB.

Κάθε κατάστημα συνήθως περιέχει ένα σύνολο πραγμάτων , που μπορεί να είναι

  • χορδές
  • αριθμοί
  • αντικείμενα
  • συστοιχίες
  • ημερομηνίες

Για παράδειγμα, μπορεί να έχετε ένα κατάστημα που περιέχει αναρτήσεις, ένα άλλο που περιέχει σχόλια.

Ένα κατάστημα περιέχει έναν αριθμό αντικειμένων που έχουν ένα μοναδικό κλειδί, το οποίο αντιπροσωπεύει τον τρόπο με τον οποίο μπορεί να αναγνωριστεί ένα αντικείμενο.

Μπορείτε να αλλάξετε αυτά τα καταστήματα χρησιμοποιώντας συναλλαγές, εκτελώντας λειτουργίες προσθήκης, επεξεργασίας και διαγραφής και επανάληψη των στοιχείων που περιέχουν.

Από την έλευση των Υποσχέσεων στο ES6 και την επακόλουθη μετάβαση των API στη χρήση υποσχέσεων, το API IndexedDB φαίνεται λίγο παλιό σχολείο .

Ενώ δεν υπάρχει τίποτα λάθος σε αυτό, σε όλα τα παραδείγματα που θα εξηγήσω, θα χρησιμοποιήσω το IndexedDB Promised Library από τον Jake Archibald, το οποίο είναι ένα μικροσκοπικό στρώμα πάνω από το IndexedDB API για να είναι πιο εύκολο στη χρήση.

Αυτή η βιβλιοθήκη χρησιμοποιείται επίσης σε όλα τα παραδείγματα στον ιστότοπο του Google Developers σχετικά με το IndexedDB

Δημιουργία βάσης δεδομένων IndexedDB

Ο απλούστερος τρόπος είναι να χρησιμοποιήσετε το unkg , προσθέτοντάς το στην κεφαλίδα της σελίδας:

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

Πριν χρησιμοποιήσετε το IndexedDB API, βεβαιωθείτε πάντα ότι ελέγχετε για υποστήριξη στο πρόγραμμα περιήγησης, παρόλο που είναι ευρέως διαθέσιμο, δεν γνωρίζετε ποτέ ποιο πρόγραμμα περιήγησης χρησιμοποιεί ο χρήστης:

(() => { '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 παράμετροι είναι το όνομα της βάσης δεδομένων και το verson. Το τρίτο param, το οποίο είναι προαιρετικό, είναι ένα αντικείμενο που περιέχει μια συνάρτηση που ονομάζεται μόνο εάν ο αριθμός έκδοσης είναι υψηλότερος από την τρέχουσα εγκατεστημένη έκδοση βάσης δεδομένων . Στο σώμα λειτουργίας μπορείτε να αναβαθμίσετε τη δομή (καταστήματα και ευρετήρια) του 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