Apprendre à utiliser IndexedDB et le stockage des données en Javascript

IndexedDB est l’une des solution de stockage introduites dans les navigateurs au fil des années.

Il s’agit d’une base de données clé/valeur (une base de données noSQL) considérée comme la solution définitive pour le stockage des données dans les navigateurs.

C’est une API asynchrone, ce qui signifie que l’exécution du code ne bloquera pas le reste de l’execution de votre programme, offrant une expérience non négligeable aux utilisateurs. Il peut stocker une quantité indéfinie de données, bien qu’une fois au-dessus d’un certain seuil, l’utilisateur est invité à autoriser le site à pouvoir stocker plus de données.

Ils existent d’autres méthodes, les cookies et le Web Storage ( localStorage et sessionStorage ), Le stockage local/session a l’inconvénient d’être limité à une petite taille, les navigateurs offrant du 2MB à 10MB d’espace par site.

Bien que vous puissiez techniquement créer plusieurs bases de données par site, vous créez généralement une seule base de données, et à l’intérieur de cette base de données, vous pouvez créer plusieurs stockage d’objets.

Une base de données est privée à un domaine, de sorte que tout autre site ne peut pas accéder à une autre base IndexedDB.

Chaque magasin d’objets contient généralement un ensemble de choses, qui peuvent être utilisé :

  • objects
  • arrays
  • strings
  • numbers
  • dates

Par exemple, vous pouvez avoir un magasin qui contient des messages, un autre qui contient des commentaires.

Un magasin contient un certain nombre de d’objets qui possèdent une clé unique, qui représente la façon dont un objet peut être identifié.

Vous pouvez modifier ces objets à l’aide de transactions, en effectuant des opérations d’ajout, de modification, de suppression et d’itération sur les éléments qu’ils contiennent.

Depuis l’avènement de Promises dans ES6, et le passage subséquent des API à l’utilisation des promesses, l’API IndexedDB semble un peu vieille école.

Bien qu’il n’y ait rien de mal à cela, dans tous les exemples que j’expliquerai, j’utiliserai la bibliothèque promise IndexedDB de Jake Archibald, qui est une petite couche sur l’API IndexedDB pour la rendre plus facile à utiliser.

Cette bibliothèque est également utilisée sur tous les exemples sur le site Google Developers concernant IndexedDB


Créer une base de données IndexedDB

La façon la plus simple est d’utiliser unpkg, en l’ajoutant à l’en-tête de la page :

<script type="module">
import { openDB, deleteDB } from 'https://unpkg.com/idb?module'
</script>

Avant d’utiliser l’API IndexedDB, assurez-vous de toujours vérifier si le navigateur est compatible, même s’il est largement disponible, vous ne savez jamais quel navigateur l’utilisateur utilise :

(async () => {
  'use strict'

  if (!('indexedDB' in window)) {
    console.warn('IndexedDB not supported')
    return
  }
})()

Comment créer une base de données IndexedDB

Utiliser openDB():

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

Les 2 premiers paramètres sont le nom de la base de données et le version. Le troisième paramètre, qui est facultatif, est un objet qui contient une fonction appelée uniquement si le numéro de version est supérieur à la version actuelle de la base de données installée. Dans le corps de fonction, vous pouvez mettre à niveau la structure (points de vente et index) de la base de données.

Ajout de données dans un store

Ajout de données lors de la création du store, initialisation du store

Pour ajouter des données, il faut utiliser la méthode put du store d’objets, mais nous devons d’abord initialiser celui-ci avec db.createObjectStore() lorsque nous le créons.

Lors de l’utilisation de put, la valeur est le premier argument, la clé est le second. C’est parce que si vous spécifiez keyPath lors de la création du store d’objets, vous n’avez pas besoin d’entrer le nom de clé sur chaque requête put(), vous pouvez simplement écrire la valeur.

Ceci remplit store0 dès que nous l’avons créé :

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

Ajout de données lorsque le point de vente est déjà créé, à l’aide de transactions

Pour ajouter des éléments plus tard, vous devez créer une transaction en lecture/écriture qui assure l’intégrité de la base de données (si une opération échoue, toutes les opérations de la transaction sont annulées et l’état revient à son état initiale).

Pour cela, utilisez une référence à l’objet dbPromise que nous avons obtenu en appelant openDB, et lancez :

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

Obtenir des données d’un point de vente

Obtenir un article d’un store d’objets: get()

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

Obtenir tous les articles d’un store d’objets: getAll()

Obtenir toutes les clés stockées

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

Obtenir toutes les valeurs stockées

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

Suppression de données d’IndexedDB

Suppression de la base de données, d’un store d’objets et de données

Supprimer entièrement une base de données IndexedDB

const dbName="mydbname"
await deleteDB(dbName)

Pour supprimer des données dans un store d’objets

Nous utilisons une transaction :

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

  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 à partir d’une version précédente d’une base de données

Le troisième paramètre (facultatif) de la fonction openDB() est un objet qui peut contenir une fonction de mise à jour appelée uniquement si le numéro de version est supérieur à la version de base de données installée. Dans ce corps de fonction, vous pouvez mettre à jour la structure (points de vente et index) de la base de données :

const name="mydbname"
const version = 1
openDB(name, version, {
  upgrade(db, oldVersion, newVersion, transaction) {
    console.log(oldVersion)
  }
})

Dans ce rappel, vous pouvez vérifier à partir de quelle version l’utilisateur effectue la mise à jour et effectuer certaines opérations en conséquence.

Vous pouvez effectuer une migration à partir d’une version de base de données précédente en utilisant cette syntaxe

(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: 
          // un store introduit dans la version 1
          db.createObjectStore('store1')
        case 1:
          // supprimer l'ancien point de vente dans la version 2, en créer un nouveau
          db.createObjectStore('store2', { keyPath: 'name' })
      }
      db.createObjectStore(storeName)
    }
  })
})()

Clé unique

createObjectStore()comme vous pouvez le voir dans le cas où 1 accepte un deuxième paramètre qui indique la clé d’index de la base de données. Ceci est très utile lorsque vous stockez des objets : les appels put() n’ont pas besoin d’un second paramètre, mais peuvent simplement prendre la valeur (un objet) et la clé sera mappée à la propriété de l’objet qui a ce nom.

L’index vous donne un moyen de récupérer une valeur plus tard par cette clé spécifique, et il doit être unique (chaque élément doit avoir une clé différente).

Une clé peut être réglée sur incrémentation automatique, vous n’avez donc pas besoin de la conserver sur le code client :

db.createObjectStore('notes', { autoIncrement: true })

Utilisez l’incrémentation automatique si vos valeurs ne contiennent pas déjà une clé unique.


Vérifier l’existence d’un store d’objets

Vous pouvez vérifier si un store d’objets existe déjà en appelant la méthode objectStoreNames():

const storeName="store1"

if (!db.objectStoreNames.contains(storeName)) {
  db.createObjectStore(storeName)
}

Supprimer d’IndexedDB

Suppression de la base de données, d’un store d’objets et de données

Supprimer une base de données

await deleteDB('mydb')

Supprimer un store d’objets

Une liste d’objets ne peut être supprimée dans le callback qu’à l’ouverture d’une db, et ce callback n’est appelé que si vous spécifiez une version supérieure à celle qui est actuellement installée :

const db = await openDB('dogsdb', 2, {
  upgrade(db, oldVersion, newVersion, transaction) {
    switch (oldVersion) {
      case 0:
        // un store introduit dans la version 1
        db.createObjectStore('store1')
      case 1:
        // supprimer l'ancien point de vente dans la version 2, en créer un nouveau
        db.deleteObjectStore('store1')
        db.createObjectStore('store2')
    }
  }
})

Pour supprimer des données dans un store d’objets, utilisez une transaction

const key = 232

const db = await openDB(/*...*/)
const tx = await db.transaction('store', 'readwrite')
const store = await tx.objectStore('store')
await store.delete(key)
await tx.complete
Nouveau Tutoriel

Newsletter

Ne manquez jamais les nouveaux conseils, tutoriels et autres.

Pas de spam, jamais. Nous ne partagerons jamais votre adresse électronique et vous pouvez vous désabonner à tout moment.