W3docs

JavaScript IndexedDB

Aprende JavaScript IndexedDB: abre una base de datos, maneja onupgradeneeded, crea almacenes de objetos e índices, ejecuta transacciones y opera registros.

IndexedDB es una potente API de almacenamiento del lado del cliente, más robusta que otras soluciones de almacenamiento local disponibles en los navegadores web. Permite almacenar y manipular de forma asíncrona grandes cantidades de datos estructurados en aplicaciones web. IndexedDB es ideal para aplicaciones que requieren almacenamiento de datos sin conexión, alto rendimiento y capacidades de consulta avanzadas sin depender de una conexión de red.

Este capítulo cubre todo lo que necesitas para empezar a usar IndexedDB: abrir una base de datos y gestionar actualizaciones de versión, crear almacenes de objetos e índices, ejecutar transacciones y realizar el ciclo CRUD completo (agregar, obtener, actualizar, eliminar), incluyendo la iteración con cursores y las consultas a través de índices.

Cuándo usar IndexedDB

IndexedDB puede almacenar casi cualquier valor JavaScript — objetos, arrays, fechas, blobs y archivos — no solo strings, y puede contener cientos de megabytes, muy por encima del límite de ~5 MB de localStorage y sessionStorage. Es un almacén NoSQL clave/valor transaccional con índices, lo que lo convierte en la elección correcta para:

  • Aplicaciones offline-first que necesitan funcionar sin conexión de red.
  • Caché de grandes conjuntos de datos como respuestas de API, documentos o archivos multimedia.
  • Consultas de registros por campos indexados en lugar de cargar todo en memoria.

Si solo necesitas persistir unos pocos valores string pequeños, opta por las APIs de Web Storage más sencillas. Consulta el capítulo Storage API para ver una descripción general de cómo el navegador gestiona las cuotas de almacenamiento entre estos mecanismos.

La API asíncrona basada en eventos

Cada operación de IndexedDB es asíncrona y basada en eventos. Las llamadas como indexedDB.open() o store.get() devuelven un objeto request inmediatamente; el resultado real llega más tarde a través de los manejadores de eventos onsuccess / onerror. Tu código nunca se bloquea esperando E/S de disco. Por esto, no puedes leer un resultado de forma síncrona justo después de emitir una solicitud — debes esperar a que se dispare el evento. (El código moderno a menudo envuelve estas solicitudes en Promises, pero la API nativa en sí es basada en callbacks, que es lo que usan los ejemplos a continuación.)

Configuración de una base de datos IndexedDB

Paso 1: Abrir una base de datos

Para usar IndexedDB, el primer paso es abrir una base de datos con indexedDB.open(name, version). El segundo argumento opcional es un número de versión entero. Si la base de datos no existe, o la versión solicitada es superior a la almacenada, se dispara el evento onupgradeneeded — este es el único lugar donde se permite cambiar la estructura de la base de datos (crear o eliminar almacenes de objetos e índices).

La llamada devuelve una solicitud y puede disparar tres eventos:

  • onsuccess — la base de datos se abrió y está lista para usar (event.target.result es el IDBDatabase).
  • onerror — la apertura falló.
  • onupgradeneeded — se necesita un cambio de esquema (ver Paso 2).

Aquí se muestra cómo crear o abrir una base de datos IndexedDB. Tras una operación exitosa, cerramos la base de datos para evitar efectos secundarios no deseados en otros ejemplos. Puedes omitir este paso en tu propio código o incluirlo si es necesario.

Advertencia: Llamar a deleteDatabase() eliminará todos los datos de esta base de datos. Esto es solo para fines de prueba y no debe usarse en producción.


javascript— editable

Paso 2: Crear almacenes de objetos

Una vez abierta la base de datos, puedes proceder a crear un almacén de objetos, que es similar a una tabla en las bases de datos relacionales. Ten en cuenta que esto solo puede hacerse durante una actualización de versión (cuando se abre la base de datos con un número de versión superior). El evento que debes escuchar es onupgradeneeded.

Al crear un almacén, eliges cómo se define la clave primaria de cada registro:

  • { keyPath: 'id' } — la clave se lee de la propiedad id de cada objeto almacenado (una clave en línea).
  • { keyPath: 'id', autoIncrement: true } — el almacén genera una clave secuencial automáticamente si no se proporciona una.
  • { autoIncrement: true } — las claves se generan y almacenan separadas del valor (una clave fuera de línea).

También se crean índices dentro de onupgradeneeded. Un índice permite buscar registros por una propiedad distinta a la clave primaria. Pasa { unique: true } para rechazar valores duplicados en esa propiedad.


javascript— editable

Transacciones

Una vez configurados la base de datos y los almacenes de objetos, necesitarás gestionar las operaciones de datos mediante transacciones. Una transacción en IndexedDB es un mecanismo que agrupa múltiples operaciones en una única unidad de trabajo que o bien tiene éxito completamente o falla completamente. Es esencial para garantizar la consistencia e integridad de los datos, especialmente cuando múltiples operaciones dependen unas de otras para producir un resultado correcto.

Cómo usar transacciones en IndexedDB

Paso 1: Iniciar una transacción

Para realizar cualquier operación en IndexedDB, se comienza creando una transacción sobre una base de datos. Una transacción se crea especificando qué almacenes de objetos involucra y el modo de la transacción, que puede ser "readonly" o "readwrite".

Paso 2: Acceder a un almacén de objetos

Dentro de una transacción, puedes acceder a uno o más almacenes de objetos para realizar operaciones de datos.

Paso 3: Realizar operaciones

Una vez que tienes acceso a un almacén de objetos, puedes ejecutar diversas operaciones como agregar, recuperar, actualizar o eliminar datos. Cada operación devuelve un objeto request que puedes usar para manejar eventos de éxito o error.

Paso 4: Completar la transacción

Una transacción se completa automáticamente una vez que todas las operaciones emitidas en ella se han resuelto, ya sea con éxito o con fallo. También puedes escuchar el evento complete en la transacción para ejecutar acciones después de que todas las operaciones hayan finalizado con éxito.

Aquí tienes un ejemplo de una transacción completa:


javascript— editable

Lectura de datos

Para recuperar datos, usa store.get(key) o un cursor para iterar sobre múltiples registros. Aquí hay ejemplos rápidos:

Recuperar un único registro:


javascript— editable

Iterar con un cursor:


javascript— editable

Consultas con índices

La clave primaria permite obtener un registro cuando ya conoces su clave. Un índice permite buscar por otra propiedad — por ejemplo, encontrar un libro por su title. Accede a un índice con store.index(name) y luego llama a get(), getAll() u openCursor() sobre él, igual que sobre un almacén.

Buscar un registro por una propiedad indexada:


javascript— editable

También puedes restringir una consulta a un rango de claves con IDBKeyRange (por ejemplo, IDBKeyRange.bound('A', 'M') para obtener todos los libros cuyo título comience entre A y M), pasando el rango a getAll() u openCursor().

Actualización y eliminación de registros

Para modificar datos existentes, usa store.put() con la misma clave. Para eliminar datos, usa store.delete(key).

Actualizar un registro:


javascript— editable

Eliminar un registro:


javascript— editable

Cómo ver el contenido de IndexedDB en tu navegador

Después de almacenar y manipular datos, puede que quieras inspeccionar lo que realmente está guardado en tu navegador. La mayoría de los navegadores modernos muestran lo que está almacenado en IndexedDB. A continuación, se muestra el ejemplo de las herramientas de desarrollador de Chrome:

IndexedDB

Buenas prácticas para el uso de transacciones

Para garantizar que tu implementación de IndexedDB sea fiable y eficiente, sigue estas pautas:

  1. Minimiza el alcance: Mantén las transacciones lo más pequeñas posible, tanto en número de operaciones como en duración. Esto reduce la probabilidad de conflictos y mejora el rendimiento.
  2. Manejo de errores: Implementa siempre el manejo de errores tanto a nivel de solicitud como de transacción. Esto ayuda a diagnosticar problemas y evitar actualizaciones parciales que podrían llevar a la corrupción de datos.
  3. Concurrencia: Ten en cuenta que, aunque IndexedDB es asíncrono y no bloqueante, las transacciones sobre la misma base de datos se ponen en cola y se ejecutan en serie para evitar condiciones de carrera e inconsistencias.

Conclusión

IndexedDB proporciona una plataforma robusta para la gestión compleja de datos en aplicaciones web, lo que lo convierte en una herramienta esencial para los desarrolladores web modernos. Mediante la implementación adecuada de sus características, los desarrolladores pueden almacenar, recuperar, actualizar y eliminar datos del lado del cliente de manera eficiente, mejorando el rendimiento de la aplicación y la experiencia del usuario.

Para necesidades de almacenamiento más simples y para comprender el panorama más amplio del almacenamiento en el navegador, consulta estos capítulos relacionados:

  • localStorage y sessionStorage — almacenamiento clave/valor ligero para pequeñas cantidades de datos string.
  • The Storage API — cómo el navegador gestiona las cuotas de almacenamiento y la persistencia entre mecanismos.
  • Trabajar con JSON — serialización de datos, útil al mover objetos hacia y desde el almacenamiento.

Práctica

Práctica
¿Cuáles son las características de IndexedDB en JavaScript?
¿Cuáles son las características de IndexedDB en JavaScript?
Was this page helpful?