logo oujood
🔍

IndexedDB HTML5

IndexedDB est une base de données intégrée au navigateur. Elle permet de stocker des volumes importants de données structurées côté client, avec des index pour des recherches rapides — le tout de façon asynchrone, sans bloquer la page.

OUJOOD.COM

localStorage et sessionStorage couvrent bien les petits besoins : préférences, état de formulaire, quelques Ko de données. Mais dès que vous avez besoin de stocker des centaines d'enregistrements, de faire des recherches, ou de travailler hors connexion avec une vraie structure de données, ces APIs montrent leurs limites. C'est là qu'IndexedDB entre en jeu.

IndexedDB est une base de données orientée objets, intégrée nativement dans tous les navigateurs modernes. Elle stocke des objets JavaScript directement — pas besoin de tout convertir en chaîne. Sa capacité de stockage se compte en dizaines ou centaines de Mo selon le navigateur et les permissions accordées par l'utilisateur.

Concepts clés avant de commencer

IndexedDB fonctionne différemment d'une base SQL classique. Quelques notions à bien avoir en tête :

  • Base de données : un conteneur lié à un domaine, avec un numéro de version.
  • Object Store : l'équivalent d'une table. On y stocke des objets JS identifiés par une clé.
  • Transaction : toute opération (lecture ou écriture) passe par une transaction. C'est le mécanisme qui garantit la cohérence des données.
  • Index : permet de rechercher des enregistrements par d'autres propriétés que la clé principale.
  • Asynchrone : toutes les opérations sont non bloquantes. On travaille avec des événements (onsuccess, onerror) ou des Promises.

Ouvrir une base de données

La première étape est toujours d'ouvrir (ou créer) la base. Si elle n'existe pas encore, le navigateur la crée automatiquement. L'événement onupgradeneeded est le seul endroit où l'on peut créer ou modifier la structure des object stores :

Exemple :   📋 Copier le code

// Ouvrir la base "maBoutique" en version 1
const requete = indexedDB.open('maBoutique', 1);

// Déclenché uniquement lors de la création ou d'un changement de version
requete.onupgradeneeded = (event) => {
  const db = event.target.result;

  // Créer un object store "produits" avec un id auto-incrémenté
  const store = db.createObjectStore('produits', {
    keyPath: 'id',
    autoIncrement: true
  });

  // Ajouter un index sur le nom pour pouvoir chercher par nom
  store.createIndex('nom', 'nom', { unique: false });
};

requete.onsuccess = (event) => {
  const db = event.target.result;
  console.log('Base ouverte :', db.name);
};

requete.onerror = (event) => {
  console.error('Erreur ouverture :', event.target.error);
};

Ajouter des enregistrements

Pour écrire dans IndexedDB, on ouvre une transaction en mode readwrite, puis on accède à l'object store cible :

Exemple :   📋 Copier le code

// Ajouter un produit dans l'object store "produits"
function ajouterProduit(db, produit) {
  const transaction = db.transaction('produits', 'readwrite');
  const store = transaction.objectStore('produits');

  const requete = store.add(produit);

  requete.onsuccess = () => {
    console.log('Produit ajouté, id :', requete.result);
  };

  requete.onerror = () => {
    console.error('Erreur ajout :', requete.error);
  };
}

// Utilisation
ajouterProduit(db, { nom: 'Clavier mécanique', prix: 89.99, stock: 15 });
ajouterProduit(db, { nom: 'Souris sans fil', prix: 34.50, stock: 42 });

Lire un enregistrement par sa clé

La lecture utilise une transaction en mode readonly (moins coûteux que readwrite). On récupère un enregistrement précis via sa clé :

Exemple :   📋 Copier le code

// Lire le produit avec l'id 1
function lireProduit(db, id) {
  const transaction = db.transaction('produits', 'readonly');
  const store = transaction.objectStore('produits');

  const requete = store.get(id);

  requete.onsuccess = () => {
    if (requete.result) {
      console.log('Produit trouvé :', requete.result);
    } else {
      console.log('Aucun produit avec cet id.');
    }
  };
}

lireProduit(db, 1);

Lire tous les enregistrements

Pour récupérer l'ensemble des enregistrements d'un object store, on utilise getAll() — disponible dans tous les navigateurs modernes :

Exemple :   📋 Copier le code

// Récupérer tous les produits
function tousLesProduits(db) {
  const transaction = db.transaction('produits', 'readonly');
  const store = transaction.objectStore('produits');

  const requete = store.getAll();

  requete.onsuccess = () => {
    console.log('Tous les produits :', requete.result);
    // requete.result est un tableau d'objets JS
  };
}

tousLesProduits(db);

Mettre à jour un enregistrement

put() remplace un enregistrement existant ou en crée un nouveau si la clé n'existe pas encore — le comportement d'un "upsert" :

Exemple :   📋 Copier le code

// Mettre à jour le stock du produit id=1
function mettreAJourProduit(db, produitModifie) {
  const transaction = db.transaction('produits', 'readwrite');
  const store = transaction.objectStore('produits');

  // put() remplace l'enregistrement complet
  const requete = store.put(produitModifie);

  requete.onsuccess = () => {
    console.log('Produit mis à jour.');
  };
}

mettreAJourProduit(db, { id: 1, nom: 'Clavier mécanique', prix: 79.99, stock: 10 });

Supprimer un enregistrement

Exemple :   📋 Copier le code

// Supprimer le produit avec l'id 2
function supprimerProduit(db, id) {
  const transaction = db.transaction('produits', 'readwrite');
  const store = transaction.objectStore('produits');

  const requete = store.delete(id);

  requete.onsuccess = () => {
    console.log('Produit supprimé.');
  };
}

supprimerProduit(db, 2);

Rechercher avec un index

L'index créé sur la propriété nom lors de l'ouverture de la base permet de chercher des enregistrements sans connaître leur clé principale :

Exemple :   📋 Copier le code

// Rechercher un produit par son nom via l'index
function rechercherParNom(db, nomRecherche) {
  const transaction = db.transaction('produits', 'readonly');
  const store = transaction.objectStore('produits');
  const index = store.index('nom');

  const requete = index.get(nomRecherche);

  requete.onsuccess = () => {
    if (requete.result) {
      console.log('Produit trouvé :', requete.result);
    } else {
      console.log('Aucun produit avec ce nom.');
    }
  };
}

rechercherParNom(db, 'Souris sans fil');

IndexedDB vs localStorage : que choisir ?

Le choix dépend du volume et de la complexité des données :

  • localStorage : préférences, petites chaînes, données simples. Rapide à mettre en place, synchrone.
  • IndexedDB : catalogues de produits, messages, données de formulaires complexes, applications hors ligne. Asynchrone, structuré, puissant.

En pratique, si vous stockez plus de 50 enregistrements ou si vos données ont une structure complexe, IndexedDB est le bon choix.

Par carabde | Mis à jour le 17 avril 2026


chapitre précédent   sommaire   chapitre suivant