HTML - Base de datos indexada
Introducción a IndexedDB
IndexedDB es una API de bajo nivel para el almacenamiento de grandes cantidades de datos estructurados en el lado del cliente en navegadores web. Proporciona una forma de almacenar y recuperar datos localmente, permitiendo que las aplicaciones web funcionen sin conexión y ofrezcan una buena experiencia de usuario.
IndexedDB es una base de datos NoSQL que utiliza un almacén de clave-valor y admite transacciones e índices. Permite almacenar y recuperar objetos JavaScript, incluyendo tipos de datos complejos como arreglos y objetos anidados. IndexedDB ofrece una mayor capacidad de almacenamiento en comparación con otras opciones de almacenamiento del lado del cliente como cookies y localStorage.
Una de las principales ventajas de usar IndexedDB es su capacidad para manejar grandes cantidades de datos estructurados de manera eficiente. Es ideal para aplicaciones que necesitan almacenamiento local persistente, como aplicaciones web sin conexión, aplicaciones web progresivas (PWA) y aplicaciones con uso intensivo de datos. IndexedDB ofrece operaciones asíncronas, lo que significa que no bloquea el hilo principal de ejecución, resultando en un mejor rendimiento y capacidad de respuesta.
En comparación con otros métodos de almacenamiento como cookies y localStorage, IndexedDB tiene varias ventajas:
Aspecto | IndexedDB | Cookies | localStorage |
---|---|---|---|
Capacidad de almacenamiento | Gigabytes | Alrededor de 4KB | Usualmente hasta 5-10MB |
Datos estructurados | Admite el almacenamiento de objetos JavaScript complejos y consultas eficientes mediante índices | Limitado al almacenamiento de pares clave-valor de cadenas | Limitado al almacenamiento de pares clave-valor de cadenas |
API asíncrona | Las operaciones son asíncronas, lo que resulta en un mejor rendimiento y capacidad de respuesta | Síncrona, puede bloquear el hilo principal | Síncrona, puede bloquear el hilo principal |
Soporte transaccional | Proporciona un modelo transaccional para operaciones de datos, asegurando la integridad de los datos | Sin soporte transaccional | Sin soporte transaccional |
Indexación y consulta | Admite la creación de índices en propiedades de almacenes de objetos para búsquedas y consultas rápidas | Sin capacidades de indexación o consulta | Sin capacidades de indexación o consulta |
Al usar IndexedDB, los desarrolladores web pueden crear aplicaciones que funcionen bien tanto en línea como sin conexión, proporcionando una buena experiencia de usuario y manejando grandes cantidades de datos estructurados.
Conceptos básicos
Para trabajar con IndexedDB, necesitas comprender algunos conceptos básicos. IndexedDB se basa en un almacén de clave-valor, lo que significa que los datos se almacenan y recuperan utilizando claves únicas asociadas a cada valor.
En el núcleo de IndexedDB están los almacenes de objetos. Un almacén de objetos es como una tabla en una base de datos tradicional y contiene los datos reales. Cada almacén de objetos tiene un nombre y puede almacenar objetos JavaScript de cualquier tipo, incluyendo estructuras de datos complejas. Los almacenes de objetos se crean dentro de una base de datos y se utilizan para organizar y agrupar datos relacionados.
Consejo: Creando un almacén de objetos
let request = indexedDB.open("MyDatabase", 1);
request.onupgradeneeded = function(event) {
let db = event.target.result;
let objectStore = db.createObjectStore("MyObjectStore", { keyPath: "id" });
};
Las transacciones son una parte fundamental de IndexedDB. Todas las operaciones de datos, como leer, escribir o eliminar datos, deben ocurrir dentro de una transacción. Las transacciones proporcionan una forma de agrupar múltiples operaciones y mantener la integridad de los datos. Pueden ser de solo lectura o de lectura-escritura, dependiendo del tipo de operaciones que se realicen. Si alguna operación dentro de una transacción falla, toda la transacción se revierte y la base de datos permanece sin cambios.
Consejo: Usando una transacción
let db = event.target.result;
let transaction = db.transaction(["MyObjectStore"], "readwrite");
let objectStore = transaction.objectStore("MyObjectStore");
let request = objectStore.add({ id: 1, name: "John Doe" });
request.onsuccess = function(event) {
console.log("Los datos se han añadido a tu base de datos.");
};
request.onerror = function(event) {
console.log("No se pudieron añadir los datos a tu base de datos.");
};
Los índices son otro concepto importante en IndexedDB. Un índice es una forma de buscar y recuperar datos de un almacén de objetos basándose en una propiedad específica o un conjunto de propiedades. Los índices te permiten encontrar datos rápidamente sin tener que recorrer todo el almacén de objetos. Puedes crear índices en cualquier propiedad de los objetos almacenados en un almacén de objetos, y también puedes crear índices compuestos que combinen múltiples propiedades.
Consejo: Creando un índice
let objectStore = db.createObjectStore("MyObjectStore", { keyPath: "id" });
objectStore.createIndex("name", "name", { unique: false });
Configuración de IndexedDB
Antes de empezar a usar IndexedDB en tu aplicación web, necesitas configurarlo. Esto implica verificar la compatibilidad del navegador, abrir una base de datos, crear almacenes de objetos y definir índices.
Es importante comprobar si el navegador es compatible con IndexedDB. Puedes hacerlo verificando si la propiedad indexedDB
existe en el objeto window
.
Consejo: Comprobación de compatibilidad con IndexedDB
if (window.indexedDB) {
console.log("IndexedDB es compatible");
} else {
console.log("IndexedDB no es compatible");
}
Una vez que hayas confirmado que IndexedDB es compatible, el siguiente paso es abrir una base de datos. Puedes abrir una base de datos llamando al método open()
en el objeto indexedDB
. Este método toma dos parámetros: el nombre de la base de datos y el número de versión. Si la base de datos no existe, se creará; de lo contrario, se abrirá la base de datos existente.
Consejo: Apertura de una base de datos
let request = indexedDB.open("MiBaseDeDatos", 1);
request.onerror = function(event) {
console.log("Error al abrir la base de datos");
};
request.onsuccess = function(event) {
let db = event.target.result;
console.log("Base de datos abierta con éxito");
};
Al abrir una base de datos, también puedes especificar un número de versión. Si el número de versión es mayor que la versión existente, se activará el evento onupgradeneeded
, permitiéndote cambiar la estructura de la base de datos, como crear o modificar almacenes de objetos e índices.
Dentro del manejador de eventos onupgradeneeded
, puedes crear almacenes de objetos utilizando el método createObjectStore()
en el objeto de la base de datos. Debes proporcionar un nombre para el almacén de objetos y especificar la ruta de la clave, que es la propiedad que identifica de manera única cada objeto en el almacén.
Consejo: Creación de un almacén de objetos
request.onupgradeneeded = function(event) {
let db = event.target.result;
let objectStore = db.createObjectStore("MiAlmacenDeObjetos", { keyPath: "id" });
};
Después de crear un almacén de objetos, puedes definir índices en propiedades específicas de los objetos almacenados en el almacén de objetos. Los índices te permiten buscar y obtener datos basados en esas propiedades. Para crear un índice, puedes usar el método createIndex()
en el almacén de objetos.
Consejo: Definición de índices
request.onupgradeneeded = function(event) {
let db = event.target.result;
let objectStore = db.createObjectStore("MiAlmacenDeObjetos", { keyPath: "id" });
objectStore.createIndex("nombre", "nombre", { unique: false });
objectStore.createIndex("edad", "edad", { unique: false });
};
Creamos dos índices: uno en la propiedad "nombre" y otro en la propiedad "edad". El parámetro unique
especifica si los valores del índice deben ser únicos o no.
Realización de operaciones CRUD
Creación de datos
Para añadir datos a un almacén de objetos en IndexedDB, es necesario usar transacciones. Primero, abre una transacción en el almacén de objetos deseado con el modo "readwrite". Luego, obtén una referencia al almacén de objetos usando el método objectStore()
en el objeto de transacción. Finalmente, usa el método add()
o put()
en el almacén de objetos para añadir los datos.
Consejo: Añadir datos a IndexedDB
let db;
let request = indexedDB.open("MyDatabase", 1);
request.onsuccess = function(event) {
db = event.target.result;
addData({ id: 1, name: "John Doe", age: 25 });
};
function addData(data) {
let transaction = db.transaction(["MyObjectStore"], "readwrite");
let objectStore = transaction.objectStore("MyObjectStore");
let request = objectStore.add(data);
request.onsuccess = function(event) {
console.log("Datos añadidos con éxito");
};
request.onerror = function(event) {
console.log("Error al añadir datos");
};
}
El método add()
se usa para añadir nuevos datos, mientras que el método put()
puede usarse para añadir nuevos datos o actualizar datos existentes si la clave ya existe.
Es importante manejar los errores que puedan ocurrir durante el proceso de adición de datos. Puedes usar el manejador de eventos onerror
en el objeto de solicitud para capturar y manejar cualquier error.
Lectura de datos
Para obtener datos de un almacén de objetos, puedes usar el método get()
en el almacén de objetos. Necesitas proporcionar la clave de los datos que quieres obtener.
Consejo: Obtener datos de IndexedDB
let transaction = db.transaction(["MyObjectStore"], "readonly");
let objectStore = transaction.objectStore("MyObjectStore");
let request = objectStore.get(1);
request.onsuccess = function(event) {
let data = event.target.result;
console.log("Datos recuperados:", data);
};
Si quieres buscar datos basados en una propiedad específica, puedes usar índices. Primero, obtén una referencia al índice usando el método index()
en el almacén de objetos. Luego, usa el método get()
en el índice para obtener datos basados en la clave del índice.
Consejo: Usar índices para obtener datos
let transaction = db.transaction(["MyObjectStore"], "readonly");
let objectStore = transaction.objectStore("MyObjectStore");
let index = objectStore.index("name");
let request = index.get("John Doe");
request.onsuccess = function(event) {
let data = event.target.result;
console.log("Datos recuperados:", data);
};
Para consultas más avanzadas o para recorrer múltiples entradas de datos, puedes usar cursores. Los cursores te permiten recorrer todos los datos en un almacén de objetos o índice. Puedes abrir un cursor usando el método openCursor()
en el almacén de objetos o índice.
Consejo: Usar cursores en IndexedDB
let transaction = db.transaction(["MyObjectStore"], "readonly");
let objectStore = transaction.objectStore("MyObjectStore");
let request = objectStore.openCursor();
request.onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
console.log("Clave:", cursor.key);
console.log("Datos:", cursor.value);
cursor.continue();
} else {
console.log("No hay más datos");
}
};
En el ejemplo anterior, abrimos un cursor en el almacén de objetos. El manejador de eventos onsuccess
se llama para cada entrada de datos. Podemos acceder a la clave y al valor de la entrada actual usando cursor.key
y cursor.value
, respectivamente. Para ir a la siguiente entrada, llamamos al método continue()
en el cursor.
Actualización de datos
Para actualizar datos existentes en un almacén de objetos, puedes usar el método put()
. Funciona de manera similar al método add()
, pero si la clave ya existe, actualizará los datos correspondientes.
Consejo: Actualizar datos en IndexedDB
let transaction = db.transaction(["MyObjectStore"], "readwrite");
let objectStore = transaction.objectStore("MyObjectStore");
let updatedData = { id: 1, name: "John Doe", age: 26 };
let request = objectStore.put(updatedData);
request.onsuccess = function(event) {
console.log("Datos actualizados con éxito");
};
También puedes actualizar campos específicos de una entrada de datos existente usando el método put()
. Primero, obtén los datos usando el método get()
, actualiza los campos deseados y luego usa put()
para guardar los cambios.
Consejo: Actualizar parcialmente datos en IndexedDB
let transaction = db.transaction(["MyObjectStore"], "readwrite");
let objectStore = transaction.objectStore("MyObjectStore");
let request = objectStore.get(1);
request.onsuccess = function(event) {
let data = event.target.result;
data.age = 27;
let updateRequest = objectStore.put(data);
updateRequest.onsuccess = function(event) {
console.log("Datos actualizados con éxito");
};
};
Al actualizar datos, ten en cuenta el control de versiones y los cambios de esquema. Si necesitas cambiar la estructura de tus almacenes de objetos o índices, debes manejarlo en el manejador de eventos onupgradeneeded
y versionar adecuadamente tu base de datos.
Eliminación de datos
Para eliminar datos de un almacén de objetos, puedes usar el método delete()
en el almacén de objetos. Necesitas proporcionar la clave de los datos que quieres eliminar.
Consejo: Eliminar datos de IndexedDB
let transaction = db.transaction(["MyObjectStore"], "readwrite");
let objectStore = transaction.objectStore("MyObjectStore");
let request = objectStore.delete(1);
request.onsuccess = function(event) {
console.log("Datos eliminados con éxito");
};
Si quieres borrar un almacén de objetos completo, puedes usar el método clear()
en el almacén de objetos.
Consejo: Borrar un almacén de objetos de IndexedDB
let transaction = db.transaction(["MyObjectStore"], "readwrite");
let objectStore = transaction.objectStore("MyObjectStore");
let request = objectStore.clear();
request.onsuccess = function(event) {
console.log("Almacén de objetos borrado con éxito");
};
Para eliminar una base de datos, puedes usar el método deleteDatabase()
en el objeto indexedDB
. Esto eliminará completamente la base de datos y todos sus almacenes de objetos.
Consejo: Eliminar una base de datos de IndexedDB
let request = indexedDB.deleteDatabase("MyDatabase");
request.onsuccess = function(event) {
console.log("Base de datos eliminada con éxito");
};
Ten cuidado al eliminar datos, ya que es una operación permanente y no se puede deshacer.
Funciones avanzadas
IndexedDB tiene varias funciones avanzadas que permiten gestionar y optimizar los datos de formas más complejas. Veamos algunas de estas funciones en detalle.
Versionado y actualizaciones
IndexedDB utiliza el versionado para gestionar los cambios en la estructura de la base de datos a lo largo del tiempo. Cada base de datos tiene un número de versión asociado. Cuando se abre una base de datos con un número de versión superior al actual, se activa el evento onupgradeneeded
, lo que permite cambiar el esquema de la base de datos.
Consejo: Versionado y actualizaciones
let request = indexedDB.open("MiBaseDeDatos", 2); // Actualizar a versión 2
request.onupgradeneeded = function(event) {
let db = event.target.result;
// Realizar cambios en el esquema de la base de datos
if (event.oldVersion < 1) {
// Crear almacenes de objetos e índices para la versión 1
let objectStore = db.createObjectStore("MiAlmacenDeObjetos", { keyPath: "id" });
objectStore.createIndex("nombre", "nombre", { unique: false });
}
if (event.oldVersion < 2) {
// Hacer cambios para la versión 2
let objectStore = db.createObjectStore("OtroAlmacenDeObjetos", { keyPath: "id" });
objectStore.createIndex("categoria", "categoria", { unique: false });
}
};
En el ejemplo anterior, abrimos la base de datos con la versión 2. Si la versión actual es inferior a 2, se activa el evento onupgradeneeded
. Luego podemos comprobar la propiedad oldVersion
para encontrar la versión actual y realizar los cambios necesarios en el esquema para cada actualización de versión.
Índices y claves compuestas
Los índices en IndexedDB permiten consultar y buscar datos de manera eficiente basándose en propiedades específicas. Se pueden crear índices en propiedades individuales o crear índices compuestos que combinen múltiples propiedades.
Consejo: Índices y claves compuestas
let request = indexedDB.open("MiBaseDeDatos", 1);
request.onupgradeneeded = function(event) {
let db = event.target.result;
let objectStore = db.createObjectStore("MiAlmacenDeObjetos", { keyPath: "id" });
// Crear un índice de propiedad única
objectStore.createIndex("nombre", "nombre", { unique: false });
// Crear un índice compuesto
objectStore.createIndex("nombreEdad", ["nombre", "edad"], { unique: false });
};
En el ejemplo anterior, creamos un índice de propiedad única en la propiedad "nombre" y un índice compuesto en las propiedades "nombre" y "edad". Los índices compuestos permiten consultar datos basados en múltiples propiedades al mismo tiempo.
Transacciones y concurrencia
Las transacciones en IndexedDB aseguran que los datos sean correctos y consistentes. Todas las operaciones de la base de datos deben realizarse dentro de una transacción. Las transacciones pueden ser de solo lectura o de lectura y escritura, dependiendo del tipo de operaciones que se realicen.
IndexedDB también admite el acceso concurrente a la base de datos. Pueden estar activas múltiples transacciones al mismo tiempo, pero operan en diferentes almacenes de objetos o tienen diferentes modos de acceso (solo lectura o lectura y escritura) para evitar conflictos.
Consejo: Transacciones y concurrencia
let transaction1 = db.transaction(["AlmacenDeObjetos1"], "readonly");
let transaction2 = db.transaction(["AlmacenDeObjetos2"], "readwrite");
// Pueden estar activas múltiples transacciones de forma concurrente
transaction1.objectStore("AlmacenDeObjetos1").get(1);
transaction2.objectStore("AlmacenDeObjetos2").add({ id: 1, nombre: "Juan" });
En el ejemplo anterior, tenemos dos transacciones activas al mismo tiempo. transaction1
es de solo lectura y opera en "AlmacenDeObjetos1", mientras que transaction2
es de lectura y escritura y opera en "AlmacenDeObjetos2". Pueden proceder de forma independiente sin conflictos.
Consideraciones de rendimiento
Para optimizar el rendimiento del uso de IndexedDB, considere lo siguiente:
Consideración | Descripción |
---|---|
Usar índices apropiados | Crear índices en las propiedades que se usan con frecuencia para consultar o buscar. Los índices aceleran las operaciones de recuperación de datos. |
Minimizar el alcance de las transacciones | Mantener las transacciones lo más pequeñas posible e incluir solo las operaciones necesarias. Esto ayuda a reducir la duración del bloqueo y mejora la concurrencia. |
Usar operaciones por lotes | Si necesita realizar múltiples operaciones de escritura, considere usar operaciones por lotes como add() , put() , o delete() dentro de una sola transacción. Esto minimiza la sobrecarga de crear transacciones separadas para cada operación. |
Evitar la recuperación innecesaria de datos | Obtener solo los datos necesarios. Usar índices y rangos de claves para reducir el conjunto de resultados y evitar obtener datos innecesarios. |
Manejar grandes conjuntos de datos de manera eficiente | Si está trabajando con grandes cantidades de datos, considere usar técnicas como la paginación o la carga perezosa para cargar datos en fragmentos más pequeños según sea necesario. |
Al tener en cuenta estas consideraciones de rendimiento y utilizar bien los índices, las transacciones y la concurrencia, puede crear aplicaciones web eficientes y rápidas con IndexedDB.
Seguridad
Al usar IndexedDB para almacenar datos en una aplicación web, es importante considerar la seguridad y proteger la información sensible. Aquí hay algunos aspectos clave para manejar datos sensibles y asegurar el acceso a IndexedDB:
Manejo de datos sensibles
Si su aplicación maneja datos sensibles, como información personal o detalles financieros, debe tomar precauciones adicionales al almacenar y manejar esos datos en IndexedDB. Aquí hay algunas buenas prácticas:
-
Cifrar datos sensibles: Antes de almacenar información sensible en IndexedDB, cifrarla usando un algoritmo de cifrado fuerte. De esta manera, incluso si alguien obtiene acceso a los datos de IndexedDB, no podrán leer la información sensible sin la clave de cifrado.
-
Usar bibliotecas de cifrado seguras: Utilizar bibliotecas o algoritmos de cifrado bien establecidos y confiables, como AES (Advanced Encryption Standard), para cifrar y descifrar datos sensibles. No crear sus propios algoritmos de cifrado, ya que pueden tener vulnerabilidades.
-
Almacenar claves de cifrado de forma segura: Mantener las claves de cifrado utilizadas para cifrar y descifrar datos sensibles de forma segura. No almacenarlas en la misma base de datos que los datos cifrados. En su lugar, considerar el uso de técnicas como funciones de derivación de claves o mecanismos de almacenamiento seguro de claves proporcionados por la plataforma o el navegador.
-
Minimizar la retención de datos: Almacenar datos sensibles en IndexedDB solo cuando sea absolutamente necesario. Si los datos ya no son necesarios, eliminarlos de forma segura de la base de datos. Revisar y eliminar regularmente cualquier información sensible innecesaria para reducir el riesgo de violaciones de datos.
Asegurar el acceso a IndexedDB
Además de manejar los datos sensibles de forma segura, también debe controlar el acceso a IndexedDB para prevenir accesos o cambios no autorizados. Aquí hay algunas medidas que puede tomar:
- Usar características de seguridad del navegador: Utilizar características de seguridad del navegador como la Política del Mismo Origen y la Política de Seguridad de Contenido (CSP) para restringir el acceso a IndexedDB desde fuentes no confiables. Estas políticas ayudan a prevenir ataques de scripts entre sitios (XSS) y accesos no autorizados a IndexedDB desde diferentes orígenes.
Consejo: Ejemplo de Política del Mismo Origen
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
- Implementar autenticación de usuario: Si su aplicación requiere autenticación de usuario, asegurarse de que solo los usuarios autenticados puedan acceder a los datos de IndexedDB. Usar mecanismos de autenticación seguros, como tokens o gestión de sesiones, para verificar la identidad del usuario antes de conceder acceso a la base de datos.
Consejo: Ejemplo de Gestión Segura de Sesiones
// Ejemplo de autenticación basada en tokens
fetch('https://api.example.com/data', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + token
}
})
.then(response => response.json())
.then(data => console.log(data));
-
Aplicar controles de acceso: Implementar controles de acceso basados en roles o permisos de usuario. Decidir qué usuarios o grupos de usuarios deben tener acceso de lectura o escritura a almacenes de objetos específicos o datos dentro de IndexedDB. Usar estos controles de acceso de manera consistente en toda su aplicación.
-
Validar y sanear la entrada del usuario: Al aceptar entradas de usuario que se almacenarán en IndexedDB, validar y sanear la entrada para prevenir posibles vulnerabilidades de seguridad como inyección SQL o ataques de scripts entre sitios. Usar reglas de validación estrictas y escapar o eliminar cualquier carácter o script malicioso.
Consejo: Ejemplo de Validación de Entrada de Usuario
const entradaSaneada = entrada.replace(/[<>]/g, ''); // saneamiento simple
- Usar comunicación segura: Si su aplicación se comunica con un servidor para sincronizar datos de IndexedDB, asegurarse de que el canal de comunicación sea seguro. Usar HTTPS/SSL para cifrar los datos transmitidos entre el cliente y el servidor, previniendo la interceptación o manipulación.
Consejo: Ejemplo de Comunicación HTTPS
<form action="https://suservidor.com/enviar" method="post">
<input type="text" name="datos">
<input type="submit" value="Enviar">
</form>
Recuerde, la seguridad es un proceso continuo, y es importante mantenerse actualizado con las últimas mejores prácticas y vulnerabilidades de seguridad. Revise y actualice regularmente sus medidas de seguridad para proteger los datos sensibles y mantener segura su implementación de IndexedDB.
Ejemplos prácticos y casos de uso
IndexedDB es una herramienta potente que se puede utilizar en varios escenarios prácticos para mejorar la funcionalidad y la experiencia del usuario en aplicaciones web. Veamos algunos casos de uso comunes y ejemplos donde IndexedDB destaca.
Almacenamiento de datos sin conexión y sincronización
Uno de los principales beneficios de IndexedDB es su capacidad para almacenar datos sin conexión y permitir funcionalidad offline en aplicaciones web. Con IndexedDB, puedes almacenar datos de la aplicación localmente en el dispositivo del usuario, permitiéndoles acceder e interactuar con la aplicación incluso cuando no están conectados a internet.
Consejo: Almacenar datos sin conexión
// Almacenar datos sin conexión
function almacenarDatosSinConexion(datos) {
let transaccion = db.transaction(["MiAlmacenDeObjetos"], "readwrite");
let almacenDeObjetos = transaccion.objectStore("MiAlmacenDeObjetos");
let solicitud = almacenDeObjetos.add(datos);
solicitud.onsuccess = function(evento) {
console.log("Datos almacenados sin conexión");
};
}
// Sincronizar datos cuando hay conexión
function sincronizarDatosConServidor() {
let transaccion = db.transaction(["MiAlmacenDeObjetos"], "readonly");
let almacenDeObjetos = transaccion.objectStore("MiAlmacenDeObjetos");
let solicitud = almacenDeObjetos.openCursor();
solicitud.onsuccess = function(evento) {
let cursor = evento.target.result;
if (cursor) {
let datos = cursor.value;
enviarDatosAlServidor(datos);
cursor.continue();
} else {
console.log("Todos los datos sincronizados con el servidor");
}
};
}
// Enviar datos al servidor
function enviarDatosAlServidor(datos) {
fetch('https://api.ejemplo.com/datos', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(datos)
})
.then(respuesta => {
if (respuesta.ok) {
console.log("Datos sincronizados con el servidor");
}
});
}
La función almacenarDatosSinConexion
guarda datos en IndexedDB cuando la aplicación está sin conexión. Los datos se añaden a un almacén de objetos dentro de una transacción. Más tarde, cuando la aplicación vuelve a estar en línea, la función sincronizarDatosConServidor
usa un cursor para recorrer todos los datos almacenados y envía cada elemento de datos al servidor usando la función enviarDatosAlServidor
. De esta manera, la aplicación puede funcionar sin conexión y sincronizar los datos con el servidor cuando se restablece la conexión.
Almacenamiento en caché de datos de la aplicación
IndexedDB se puede usar como mecanismo de caché para almacenar localmente datos de acceso frecuente o de carga lenta. Al almacenar datos en caché en IndexedDB, puedes mejorar el rendimiento y la velocidad de tu aplicación web.
Consejo: Verificar caché para datos
// Verificar caché para datos
function obtenerDatosDeCache(clave) {
return new Promise((resolver, rechazar) => {
let transaccion = db.transaction(["AlmacenCache"], "readonly");
let almacenDeObjetos = transaccion.objectStore("AlmacenCache");
let solicitud = almacenDeObjetos.get(clave);
solicitud.onsuccess = function(evento) {
let datos = evento.target.result;
if (datos) {
console.log("Datos recuperados de la caché");
resolver(datos);
} else {
console.log("Datos no encontrados en la caché");
rechazar();
}
};
});
}
// Almacenar datos en caché
function almacenarDatosEnCache(clave, datos) {
let transaccion = db.transaction(["AlmacenCache"], "readwrite");
let almacenDeObjetos = transaccion.objectStore("AlmacenCache");
let solicitud = almacenDeObjetos.put(datos, clave);
solicitud.onsuccess = function(evento) {
console.log("Datos almacenados en caché");
};
}
// Obtener datos de la caché o del servidor
function obtenerDatos(clave) {
obtenerDatosDeCache(clave)
.then(datos => {
console.log("Datos recuperados de la caché:", datos);
})
.catch(() => {
fetch(`https://api.ejemplo.com/datos/${clave}`)
.then(respuesta => respuesta.json())
.then(datos => {
console.log("Datos recuperados del servidor:", datos);
almacenarDatosEnCache(clave, datos);
});
});
}
La función obtenerDatosDeCache
verifica si los datos solicitados están disponibles en la caché (IndexedDB). Si se encuentran los datos, se resuelven y se devuelven. Si los datos no se encuentran en la caché, la función rechaza, y la función obtenerDatos
obtiene los datos del servidor usando la API fetch
. Una vez que se recuperan los datos del servidor, se almacenan en la caché usando la función almacenarDatosEnCache
para accesos futuros.
Al implementar este mecanismo de caché, puedes reducir el número de solicitudes de red y mejorar la velocidad de carga de tu aplicación al servir datos desde la caché local cuando estén disponibles.
Implementación de funcionalidad de búsqueda
Las capacidades de indexación de IndexedDB lo hacen muy adecuado para implementar funcionalidades de búsqueda dentro de una aplicación web. Al crear índices en campos buscables, puedes buscar y recuperar datos rápidamente basándote en criterios específicos.
Consejo: Crear índice en campo buscable
// Crear índice en campo buscable
function crearIndiceDeBusqueda() {
let solicitud = indexedDB.open("MiBaseDeDatos", 1);
solicitud.onupgradeneeded = function(evento) {
let db = evento.target.result;
let almacenDeObjetos = db.createObjectStore("AlmacenProductos", { keyPath: "id" });
almacenDeObjetos.createIndex("nombre", "nombre", { unique: false });
};
}
// Buscar datos usando el índice
function buscarDatos(terminoBusqueda) {
let transaccion = db.transaction(["AlmacenProductos"], "readonly");
let almacenDeObjetos = transaccion.objectStore("AlmacenProductos");
let indice = almacenDeObjetos.index("nombre");
let solicitud = indice.getAll(IDBKeyRange.bound(terminoBusqueda, terminoBusqueda + '\uffff'));
solicitud.onsuccess = function(evento) {
let resultados = evento.target.result;
console.log("Resultados de búsqueda:", resultados);
};
}
// Ejemplo de uso
crearIndiceDeBusqueda();
// Añadir datos de ejemplo
let transaccion = db.transaction(["AlmacenProductos"], "readwrite");
let almacenDeObjetos = transaccion.objectStore("AlmacenProductos");
almacenDeObjetos.add({ id: 1, nombre: "Manzana", categoria: "Fruta" });
almacenDeObjetos.add({ id: 2, nombre: "Plátano", categoria: "Fruta" });
almacenDeObjetos.add({ id: 3, nombre: "Naranja", categoria: "Fruta" });
// Realizar búsqueda
buscarDatos("Man");
Creamos un índice en el campo "nombre" del almacén de objetos "AlmacenProductos" usando la función crearIndiceDeBusqueda
. Esto permite buscar eficientemente basándose en el nombre del producto.
La función buscarDatos
realiza una búsqueda usando el índice. Toma un término de búsqueda como entrada y usa el método getAll
con un IDBKeyRange
para encontrar todos los productos que coincidan con el término de búsqueda.
En el ejemplo de uso, creamos el índice de búsqueda, añadimos algunos datos de muestra al almacén de objetos "AlmacenProductos", y luego realizamos una búsqueda de productos con "Man" en su nombre. Los resultados de la búsqueda se registran en la consola.
Estos son solo algunos ejemplos de cómo se puede usar IndexedDB en escenarios prácticos. La flexibilidad y las potentes características de IndexedDB lo hacen adecuado para una amplia gama de casos de uso donde se requiere almacenamiento y manejo de datos del lado del cliente.