Guía para principiantes sobre el uso de las API de IndexedDB

Este tutorial cubre lo esencial de IndexedDB, sus funciones y cómo integrarlo en tus proyectos web.

Daniel Costa

Daniel Costa

4 July 2025

Guía para principiantes sobre el uso de las API de IndexedDB

Crear aplicaciones que funcionen sin problemas sin conexión se ha convertido en un requisito clave en el desarrollo web moderno. IndexedDB ofrece una solución potente para los desarrolladores que buscan almacenar y gestionar grandes cantidades de datos directamente en el navegador. Esta base de datos NoSQL del lado del cliente permite una gestión eficiente de los datos, lo que la hace ideal para aplicaciones web que necesitan funcionalidad sin conexión. En este artículo, exploraremos los conceptos básicos de IndexedDB, sus características clave y te guiaremos a través de los pasos para configurarla y usarla en tus proyectos web.

¿Qué es IndexedDB?

IndexedDB es una potente base de datos NoSQL del lado del cliente que permite a las aplicaciones web almacenar y gestionar datos estructurados directamente en el navegador. Proporciona una solución eficiente para gestionar grandes conjuntos de datos localmente, lo que la hace ideal para la funcionalidad sin conexión y las aplicaciones con gran cantidad de datos.

Una de las principales ventajas de IndexedDB es su capacidad para admitir aplicaciones web sin conexión. Permite a los desarrolladores almacenar cantidades sustanciales de datos, utilizar la indexación para una recuperación rápida, gestionar transacciones y navegar por los datos mediante cursores. Estas características la convierten en una excelente opción para gestionar datos complejos en aplicaciones web.

La mayoría de los navegadores web modernos, incluidos Chrome, Firefox, Safari y Edge, son compatibles con IndexedDB. Sin embargo, es importante asegurarse de que la versión de IndexedDB sea compatible con el navegador al que te diriges para tu aplicación web.

Para empezar a usar IndexedDB, el primer paso es abrir una conexión a la base de datos, que es necesaria para crearla e interactuar con ella.

💡
cuando también estés trabajando con APIs, es importante considerar cómo herramientas como Apidog pueden optimizar tu flujo de trabajo. Apidog proporciona una plataforma unificada que simplifica el diseño, las pruebas y la documentación de la API. A diferencia de otras herramientas que requieren varios pasos separados para la gestión de la API, Apidog lo reúne todo en un solo lugar con funciones como la sincronización en tiempo real y la colaboración perfecta para los equipos de desarrollo.
button

Primeros pasos con IndexedDB: Una guía completa

IndexedDB es una potente solución de almacenamiento del lado del cliente para aplicaciones web. Esta guía te guiará a través de todo, desde la configuración básica hasta las técnicas avanzadas y la implementación en el mundo real.

Configuración de IndexedDB

Creación y apertura de una base de datos

Para crear una nueva base de datos en IndexedDB, utilizarás el método indexedDB.open():

const request = indexedDB.open("MyDatabase", 1);
request.onupgradeneeded = (event) => {
  const db = event.target.result;
  // Create object stores and indexes here
};

El método toma dos parámetros: el nombre de la base de datos y el número de versión. Para abrir una base de datos existente, simplemente puedes llamar al método sin especificar un número de versión.

Control de versiones de la base de datos

IndexedDB admite el control de versiones para gestionar los cambios de esquema. Cuando abres una base de datos con un número de versión superior al existente, se activa el evento onupgradeneeded, lo que te permite actualizar el esquema de tu base de datos.

Creación de almacenes de objetos e índices

Los almacenes de objetos son contenedores para tus datos en IndexedDB:

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  // Create an object store with a key path
  const objectStore = db.createObjectStore("customers", { keyPath: "id" });
  
  // Create an index for efficient querying
  objectStore.createIndex("name", "name", { unique: false });
};

Trabajar con transacciones

Comprensión de los conceptos básicos de las transacciones

Las transacciones en IndexedDB mantienen la integridad de los datos agrupando varias operaciones en una sola unidad atómica. Se aseguran de que todos los cambios se apliquen o de que ninguno lo haga.

Creación y gestión de transacciones

const transaction = db.transaction(["customers"], "readwrite");
const objectStore = transaction.objectStore("customers");

transaction.oncomplete = (event) => {
  console.log("Transaction completed successfully");
};

transaction.onerror = (event) => {
  console.error("Transaction failed");
};

Manejo de errores y reversión

Si una operación falla, puedes usar el método abort() para revertir toda la transacción:

try {
  // Perform operations
} catch (error) {
  transaction.abort();
  console.error("Transaction aborted:", error);
}

Operaciones de datos en IndexedDB

Añadir datos

const customerData = { id: "00001", name: "John Doe", email: "john@example.com" };
const request = objectStore.add(customerData);

request.onsuccess = (event) => {
  console.log("Data added successfully");
};

Recuperación de datos

Recuperación básica de datos por clave:

const request = objectStore.get("00001");
request.onsuccess = (event) => {
  console.log("Customer data:", request.result);
};

Filtrado con índices

const index = objectStore.index("name");
const request = index.get("John Doe");

request.onsuccess = (event) => {
  console.log("Found by name:", request.result);
};

Métodos de consulta avanzados

Para consultas complejas, IndexedDB ofrece consultas de rango y consultas compuestas utilizando métodos como openCursor() e IDBKeyRange:

const range = IDBKeyRange.bound("A", "F"); // Names starting with A through F
const request = index.openCursor(range);

Actualización de registros

const updateData = { id: "00001", name: "John Smith", email: "john@example.com" };
const request = objectStore.put(updateData);

Eliminación de registros

const request = objectStore.delete("00001");
request.onsuccess = (event) => {
  console.log("Record deleted");
};

Trabajar con cursores

Comprensión de la funcionalidad del cursor

Los cursores te permiten iterar eficientemente sobre los registros en un almacén de objetos o índice, proporcionando una forma de recorrer y manipular los datos.

const request = objectStore.openCursor();
request.onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    console.log("Key:", cursor.key, "Value:", cursor.value);
    cursor.continue(); // Move to the next record
  } else {
    console.log("No more records");
  }
};

Modificación de datos mediante cursores

const transaction = db.transaction(["customers"], "readwrite");
const objectStore = transaction.objectStore("customers");
const request = objectStore.openCursor();

request.onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    if (cursor.value.status === "inactive") {
      const updateData = cursor.value;
      updateData.status = "active";
      cursor.update(updateData);
    }
    cursor.continue();
  }
};

Gestión y actualizaciones del esquema

Actualización del esquema de la base de datos

Cuando tu aplicación evoluciona, es posible que necesites modificar el esquema de tu base de datos:

const request = indexedDB.open("MyDatabase", 2); // Increase version number

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  
  // Check if the object store exists
  if (!db.objectStoreNames.contains("newStore")) {
    db.createObjectStore("newStore", { keyPath: "id" });
  }
};

Migración de datos durante las actualizaciones

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  const oldVersion = event.oldVersion;
  
  if (oldVersion < 1) {
    // First version setup
  }
  
  if (oldVersion < 2) {
    // Migrate data to new schema
    const transaction = event.target.transaction;
    const oldStore = transaction.objectStore("oldStore");
    const newStore = db.createObjectStore("newStore", { keyPath: "id" });
    
    oldStore.openCursor().onsuccess = (event) => {
      const cursor = event.target.result;
      if (cursor) {
        newStore.add(cursor.value);
        cursor.continue();
      }
    };
  }
};

Optimización del rendimiento

Operaciones masivas eficientes

Para un mejor rendimiento, utiliza operaciones masivas cuando trabajes con varios registros:

const transaction = db.transaction(["customers"], "readwrite");
const store = transaction.objectStore("customers");

// Add multiple records in a single transaction
customerList.forEach(customer => {
  store.add(customer);
});

Aprovechamiento de los índices para consultas más rápidas

Crea índices en las propiedades consultadas con frecuencia para garantizar una recuperación de datos más rápida:

objectStore.createIndex("email", "email", { unique: true });
objectStore.createIndex("lastLogin", "lastLogin", { unique: false });

Prácticas recomendadas para la gestión de conexiones

Abre las conexiones solo cuando sea necesario y ciérralas cuando hayas terminado:

let db;

function openDB() {
  const request = indexedDB.open("MyDatabase", 1);
  request.onsuccess = (event) => {
    db = event.target.result;
  };
  return request;
}

// When you're done with the database
function closeDB() {
  if (db) {
    db.close();
    db = null;
  }
}

Ejemplo del mundo real: Gestor de tareas con soporte sin conexión

Configuración de la base de datos

const request = indexedDB.open("TaskManagerDB", 1);

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  const taskStore = db.createObjectStore("tasks", { keyPath: "id", autoIncrement: true });
  
  // Create indexes for querying
  taskStore.createIndex("status", "status", { unique: false });
  taskStore.createIndex("dueDate", "dueDate", { unique: false });
};

Añadir tareas

function addTask(taskData) {
  const transaction = db.transaction(["tasks"], "readwrite");
  const taskStore = transaction.objectStore("tasks");
  
  return new Promise((resolve, reject) => {
    const request = taskStore.add({
      title: taskData.title,
      description: taskData.description,
      status: "pending",
      dueDate: taskData.dueDate,
      createdAt: new Date()
    });
    
    request.onsuccess = () => resolve(request.result);
    request.onerror = () => reject(request.error);
  });
}

Recuperación y visualización de tareas

function getAllTasks() {
  const transaction = db.transaction(["tasks"], "readonly");
  const taskStore = transaction.objectStore("tasks");
  
  return new Promise((resolve, reject) => {
    const request = taskStore.openCursor();
    const tasks = [];
    
    request.onsuccess = (event) => {
      const cursor = event.target.result;
      if (cursor) {
        tasks.push(cursor.value);
        cursor.continue();
      } else {
        resolve(tasks);
      }
    };
    
    request.onerror = () => reject(request.error);
  });
}

Actualización y eliminación de tareas

function updateTaskStatus(id, newStatus) {
  const transaction = db.transaction(["tasks"], "readwrite");
  const taskStore = transaction.objectStore("tasks");
  
  return new Promise((resolve, reject) => {
    const getRequest = taskStore.get(id);
    
    getRequest.onsuccess = () => {
      const task = getRequest.result;
      task.status = newStatus;
      task.updatedAt = new Date();
      
      const updateRequest = taskStore.put(task);
      updateRequest.onsuccess = () => resolve(true);
      updateRequest.onerror = () => reject(updateRequest.error);
    };
    
    getRequest.onerror = () => reject(getRequest.error);
  });
}

Sincronización con el servidor

function syncWithServer() {
  if (!navigator.onLine) {
    return Promise.reject(new Error("No internet connection"));
  }
  
  return getAllTasks()
    .then(tasks => {
      // Filter tasks that need syncing
      const unsynced = tasks.filter(task => !task.synced);
      
      // Send to server using fetch API
      return fetch('https://api.example.com/tasks/sync', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(unsynced)
      });
    })
    .then(response => response.json())
    .then(result => {
      // Mark tasks as synced
      const transaction = db.transaction(["tasks"], "readwrite");
      const taskStore = transaction.objectStore("tasks");
      
      result.syncedIds.forEach(id => {
        const request = taskStore.get(id);
        request.onsuccess = () => {
          const task = request.result;
          task.synced = true;
          taskStore.put(task);
        };
      });
      
      return result;
    });
}

// Listen for online events to sync automatically
window.addEventListener('online', syncWithServer);

Integración de Apidog para la gestión de API con IndexedDB

Al crear aplicaciones con IndexedDB para el almacenamiento del lado del cliente, a menudo necesitarás interactuar con las API de back-end para la sincronización de datos. Apidog proporciona una solución perfecta para gestionar estas interacciones de la API.

Por qué Apidog mejora el desarrollo de IndexedDB

A medida que desarrollas aplicaciones con capacidad sin conexión con IndexedDB, Apidog ofrece varias ventajas:

Sincronización en tiempo real: Apidog garantiza que tus puntos finales de la API utilizados para la sincronización de datos estén siempre configurados y probados correctamente, eliminando los problemas de integración cuando tu aplicación se conecta.

Respuestas de API simuladas: Al desarrollar la funcionalidad sin conexión, los motores de simulación inteligentes de Apidog te permiten simular las respuestas de la API para probar tu lógica de sincronización de IndexedDB sin un servidor en vivo.

Diseño colaborativo de API: Cuando tu equipo está trabajando simultáneamente en el almacenamiento front-end y las API de back-end, Apidog facilita la colaboración en tiempo real en las especificaciones de la API.

Al integrar Apidog en tu flujo de trabajo de desarrollo, creas un puente perfecto entre el almacenamiento del lado del cliente y el procesamiento del lado del servidor, lo que hace que tu aplicación sea más robusta y fácil de mantener.

button

Explore more

Cómo usar Lovable AI (Alternativa a Cursor para desarrolladores web)

Cómo usar Lovable AI (Alternativa a Cursor para desarrolladores web)

Aprende a crear cualquier web con Lovable en esta guía completa. Descubre procesos paso a paso, funciones innovadoras e integra herramientas gratuitas como Apidog para gestión API.

15 April 2025

Cómo usar n8n con servidores MCP

Cómo usar n8n con servidores MCP

Automatiza flujos con n8n y servidores MCP para IA. Guía técnica: configuración, APIs, nodo "MCP Server Trigger" y Apidog para pruebas.

14 April 2025

Cómo añadir claves API personalizadas a Cursor: Una guía completa

Cómo añadir claves API personalizadas a Cursor: Una guía completa

Este tutorial te guiará para configurar y gestionar claves API personalizadas en Cursor (OpenAI, Anthropic, Google y Azure).

11 April 2025

Practica el diseño de API en Apidog

Descubre una forma más fácil de construir y usar APIs