JavaScript IndexedDB
Apprenez IndexedDB en JavaScript : ouvrir une base de données, gérer onupgradeneeded, créer des object stores et des index, exécuter des transactions, et ajouter, lire, mettre à jour et supprimer des enregistrements avec des curseurs.
IndexedDB est une API de stockage côté client puissante, plus robuste que les autres solutions de stockage local disponibles dans les navigateurs web. Elle permet aux applications web de stocker et de manipuler de manière asynchrone des quantités importantes de données structurées. IndexedDB est idéale pour les applications nécessitant un stockage de données hors ligne, des performances élevées et des capacités de requêtes avancées sans dépendre d'une connexion réseau.
Ce chapitre couvre tout ce dont vous avez besoin pour commencer à utiliser IndexedDB : ouvrir une base de données et gérer les mises à niveau de version, créer des object stores et des index, exécuter des transactions, et effectuer le cycle CRUD complet (ajout, lecture, mise à jour, suppression), notamment l'itération avec des curseurs et les requêtes via des index.
Quand utiliser IndexedDB
IndexedDB peut stocker presque n'importe quelle valeur JavaScript — objets, tableaux, dates, blobs et fichiers — pas seulement des chaînes, et peut contenir des centaines de mégaoctets, bien au-delà de la limite de ~5 Mo de localStorage et sessionStorage. C'est un store clé/valeur NoSQL transactionnel avec des index, ce qui en fait le bon choix pour :
- Les applications offline-first qui doivent fonctionner sans connexion réseau.
- La mise en cache de grands ensembles de données tels que les réponses d'API, les documents ou les fichiers multimédia.
- Les requêtes sur des enregistrements par champs indexés plutôt que de tout charger en mémoire.
Si vous avez seulement besoin de persister quelques petites valeurs de type string, préférez les API Web Storage plus simples. Consultez le chapitre Storage API pour un aperçu de la façon dont le navigateur gère les quotas de stockage entre ces mécanismes.
L'API asynchrone basée sur les événements
Chaque opération IndexedDB est asynchrone et basée sur les événements. Les appels tels que indexedDB.open() ou store.get() retournent immédiatement un objet request ; le résultat réel arrive ensuite via les gestionnaires d'événements onsuccess / onerror. Votre code ne se bloque jamais en attendant les I/O disque. Pour cette raison, vous ne pouvez pas lire un résultat de manière synchrone juste après avoir émis une requête — vous devez attendre que l'événement se déclenche. (Le code moderne enveloppe souvent ces requêtes dans des Promises, mais l'API native elle-même est basée sur des callbacks, ce que les exemples ci-dessous utilisent.)
Configurer une base de données IndexedDB
Étape 1 : Ouvrir une base de données
Pour utiliser IndexedDB, la première étape consiste à ouvrir une base de données avec indexedDB.open(name, version). Le second argument optionnel est un numéro de version entier. Si la base de données n'existe pas, ou si la version demandée est supérieure à celle stockée, l'événement onupgradeneeded se déclenche — c'est le seul endroit où vous êtes autorisé à modifier la structure de la base de données (créer ou supprimer des object stores et des index).
L'appel retourne une requête et peut déclencher trois événements :
onsuccess— la base de données est ouverte et prête à être utilisée (event.target.resultest l'IDBDatabase).onerror— l'ouverture a échoué.onupgradeneeded— un changement de schéma est nécessaire (voir l'étape 2).
Voici comment créer ou ouvrir une base de données IndexedDB. Après une opération réussie, nous fermons la base de données pour éviter les effets secondaires indésirables dans d'autres exemples. Vous pouvez ignorer cette étape dans votre propre code ou l'inclure si nécessaire.
Avertissement : L'appel de deleteDatabase() effacera toutes les données de cette base de données. Cela n'est destiné qu'à des fins de test et ne doit pas être utilisé en production.
Étape 2 : Créer des object stores
Une fois la base de données ouverte, vous pouvez procéder à la création d'un object store, qui est analogue à une table dans les bases de données relationnelles. Notez que cela ne peut être fait que lors d'une mise à niveau de version (lors de l'ouverture de la base de données avec un numéro de version plus élevé). L'événement à écouter est onupgradeneeded.
Lors de la création d'un store, vous choisissez comment la clé primaire de chaque enregistrement est définie :
{ keyPath: 'id' }— la clé est lue depuis la propriétéidde chaque object stocké (une clé inline).{ keyPath: 'id', autoIncrement: true }— le store génère automatiquement une clé séquentielle si vous n'en fournissez pas.{ autoIncrement: true }— les clés sont générées et stockées séparément de la valeur (une clé out-of-line).
Vous créez également des index à l'intérieur de onupgradeneeded. Un index vous permet de rechercher des enregistrements par une propriété autre que la clé primaire. Passez { unique: true } pour rejeter les valeurs dupliquées pour cette propriété.
Transactions
Une fois votre base de données et vos object stores configurés, vous devrez gérer les opérations de données à l'aide de transactions. Une transaction dans IndexedDB est un mécanisme qui regroupe plusieurs opérations en une seule unité de travail qui réussit complètement ou échoue complètement. Elle est essentielle pour garantir la cohérence et l'intégrité des données, notamment lorsque plusieurs opérations dépendent les unes des autres pour produire un résultat correct.
Comment utiliser les transactions dans IndexedDB
Étape 1 : Démarrer une transaction
Pour effectuer toute opération dans IndexedDB, vous commencez par créer une transaction sur une base de données. Une transaction est créée en spécifiant quels object stores elle implique et le mode de la transaction, qui peut être "readonly" ou "readwrite".
Étape 2 : Accéder à un object store
Dans une transaction, vous pouvez accéder à un ou plusieurs object stores pour effectuer des opérations sur les données.
Étape 3 : Effectuer des opérations
Une fois que vous avez accès à un object store, vous pouvez exécuter diverses opérations telles que l'ajout, la récupération, la mise à jour ou la suppression de données. Chaque opération retourne un objet request que vous pouvez utiliser pour gérer les événements de succès ou d'erreur.
Étape 4 : Terminer la transaction
Une transaction se termine automatiquement une fois que toutes les opérations qui y ont été émises ont été résolues, qu'elles aient réussi ou échoué. Vous pouvez également écouter l'événement complete sur la transaction pour effectuer des actions après que toutes les opérations ont abouti avec succès.
Voici un exemple de transaction complète :
Lecture des données
Pour récupérer des données, utilisez store.get(key) ou un curseur pour itérer sur plusieurs enregistrements. Voici quelques exemples rapides :
Récupérer un seul enregistrement :
Itérer avec un curseur :
Requêtes avec des index
La clé primaire vous permet de récupérer un enregistrement lorsque vous connaissez déjà sa clé. Un index vous permet de rechercher par une autre propriété — par exemple, trouver un livre par son title. Accédez à un index avec store.index(name), puis appelez get(), getAll() ou openCursor() sur celui-ci, exactement comme sur un store.
Rechercher un enregistrement par une propriété indexée :
Vous pouvez également restreindre une requête à une plage de clés avec IDBKeyRange (par exemple IDBKeyRange.bound('A', 'M') pour récupérer tous les livres dont le titre commence entre A et M), en passant la plage à getAll() ou openCursor().
Mise à jour et suppression d'enregistrements
Pour modifier des données existantes, utilisez store.put() avec la même clé. Pour supprimer des données, utilisez store.delete(key).
Mettre à jour un enregistrement :
Supprimer un enregistrement :
Comment visualiser le contenu d'IndexedDB dans votre navigateur
Après avoir stocké et manipulé des données, vous souhaitez peut-être inspecter ce qui est réellement enregistré dans votre navigateur. La plupart des navigateurs modernes vous montrent ce qui est stocké dans IndexedDB. Voici un exemple tiré des outils de développement de Chrome :

Bonnes pratiques pour l'utilisation des transactions
Pour garantir que votre implémentation IndexedDB reste fiable et performante, suivez ces recommandations :
- Minimiser la portée : Gardez les transactions aussi petites que possible, tant en termes de nombre d'opérations que de durée. Cela réduit les risques de conflits et améliore les performances.
- Gestion des erreurs : Implémentez toujours la gestion des erreurs à la fois au niveau de la requête et au niveau de la transaction. Cela facilite le diagnostic des problèmes et évite les mises à jour partielles pouvant entraîner une corruption des données.
- Concurrence : Comprenez que, bien qu'IndexedDB soit asynchrone et non bloquant, les transactions sur la même base de données sont mises en file d'attente et exécutées en série pour éviter les conditions de course et les incohérences.
Conclusion
IndexedDB offre une plateforme robuste pour la gestion complexe des données dans les applications web, ce qui en fait un outil essentiel pour les développeurs web modernes. Grâce à une implémentation adéquate de ses fonctionnalités, les développeurs peuvent stocker, récupérer, mettre à jour et supprimer efficacement des données côté client, améliorant ainsi les performances des applications et l'expérience utilisateur.
Pour des besoins de stockage plus simples et pour comprendre l'ensemble du tableau du stockage navigateur, consultez ces chapitres connexes :
- localStorage et sessionStorage — stockage clé/valeur léger pour de petites quantités de données de type string.
- The Storage API — comment le navigateur gère les quotas de stockage et la persistance entre les différents mécanismes.
- Travailler avec JSON — sérialisation des données, utile lors du transfert d'objets vers et depuis le stockage.