Code前端首页关于Code前端联系我们

IndexedDB完全指南

terry 2年前 (2023-09-26) 阅读数 53 #后端开发
IndexedDB完整使用指南

作者原创:Chibuike Nwachukwu

原文地址:https://blog.logrocket.com/using-indexeddb-complete-guide/

翻译:井川

1写在前面 数据存储是大多数web 应用程序的重要组成部分,从用户数据跟踪到应用程序数据。随着更快、更强大的Web应用程序的快速开发,需要高效的客户端存储来帮助开发。

web 上的客户端存储多年来发生了很大变化,从用于存储用户数据的cookies WebSQL(当前已弃用)这允许开发人员将数据存储在浏览器内的SQL 数据库中,这使得了解SQL的用户可以轻松创建强大的应用程序。

IndexedDBWebSQL 的替代品,它提供比以前的实例更多的存储容量。在本教程中,我们将探索如何使用和配置 IndexedDB 来存储 Web 应用程序的数据,以及如何使用可用的 API 操作其数据。

2IndexedDB是什么?

IndexedDB 是用于客户端存储的低级 API。它是一个成熟、持久的NoSQL存储系统,可在浏览器中使用,并允许您存储不同类型的数据,例如:

  • 文件或Blob
  • 图像和视频
  • 结构

IndexedDB可用于缓存、PWA、游戏等多种场景,还支持交易。它的开发是为了有效地满足web 应用程序的各种需求。

3 设置我们的项目

我们不会进行任何花哨的设置,因为 IndexedDB 在网络上本地运行。首先,创建一个新目录来安装项目:

mkdir indexed-db && cd indexed-db

现在我们将通过创建脚本来创建一个文件来查看我们的应用程序 index.js index.html 一个要存储的文件我们的应用程序逻辑:

touch index.html index.js styles.css

4 在索引数据库中存储数据

要了解使用此数据库的好处并了解如何与 API 进行交互,我们将创建一个基本任务应用程序。让我们启用一个添加函数来查看数据如何保存到数据库,另一个函数来查看所有任务,以及一个删除函数来查看 GET API功能删除

打开在上一节中创建的index.html并添加以下代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TODO APP</title>
    <script  defer></script>
    <link href="style.css" rel="stylesheet">
</head>
<body>
    <h1>TODO APP</h1>
    <section>
        <aside class="view">
            <h2>TODOs</h2>
            <div class="todos">
                <ol></ol>
            </div>
        </aside>
        <aside class="add"> 
            <h2>Add Todo</h2>
            <form>
              <div>
                <label for="title">Todo title</label>
                <input id="title" type="text" required>
              </div>
              <div>
                <label for="desc">Todo description</label>
                <input id="desc" type="text" required>
              </div>
              <div>
                <button>Save</button>
              </div>
            </form>
        </aside>
    </section>
</body>
</html>

这将创建我们的Web应用程序的基础架构。我们在这里主要做两件事:首先,我们创建一个部分来显示/查看数据库中存储的所有任务项,其次,我们创建一个部分来将任务项添加到数据库中。

我们还为应用程序添加了一些基本样式。打开文件 styles.css 并添加以下内容:

html {
    font-family: sans-serif;
  }

  body {
    margin: 0 auto;
    max-width: 800px;
  }

  header, footer {
    background-color: blue;
    color: white;
    padding: 0 20px;
  }

  .add, .view {
    padding: 30px;
    width: 40%;
  }

  .add {
    background: #ebe6e6; 
  }
  section {
    padding: 10px;
    background: #3182d4;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
  }

  h1 {
    margin: 0;
  }

  ol {
    list-style-type: none;
  }

  div {
    margin-bottom: 10px;
  }

文件 index.js 是应用程序的核心,因为它包含应用程序中使用的文件和 IndexedDB之间的互动逻辑。

首先我们需要创建一个数据库;然后,我们可以通过创建一个对象存储(类似于 SQL 中的表)来初始化它,我们将使用该对象存储来存储每个项目的详细信息。打开文件 index.js,添加以下逻辑:

let db;
const openOrCreateDB = window.indexedDB.open('todo_db', 1);

openOrCreateDB.addEventListener('error', () => console.error('Error opening DB'));

openOrCreateDB.addEventListener('success', () => {
  console.log('Successfully opened DB');
  db = openOrCreateDB.result;
});

openOrCreateDB.addEventListener('upgradeneeded', init => {
  db = init.target.result;

  db.onerror = () => {
    console.error('Error loading database.');
  };

  const table = db.createObjectStore('todo_tb', { keyPath: 'id', autoIncrement:true });

  table.createIndex('title', 'title', { unique: false });
  table.createIndex('desc', 'desc', { unique: false });
});

如上所示,创建了一个名为 index.js 的数据库,然后创建了一个名为 的对象存储创建了 todo_db ,其中包含两个索引:title desc。这些索引允许它们的值在存储中重复,类似于在SQL中创建表,然后创建两列。

然后,要添加功能保存,我们继续检索在表单中输入的值,然后将它们存储到数据库中:

const todos = document.querySelector('ol');
const form = document.querySelector('form');
const todoTitle = document.querySelector('#title');
const todoDesc = document.querySelector('#desc');
const submit = document.querySelector('button');

form.addEventListener('submit', addTodo);

function addTodo(e) {
  e.preventDefault();
  const newTodo = { title: todoTitle.value, body: todoDesc.value };
  const transaction = db.transaction(['todo_tb'], 'readwrite');
  const objectStore = transaction.objectStore('todo_tb');
  const query = objectStore.add(newTodo);
  query.addEventListener('success', () => {
    todoTitle.value = '';
    todoDesc.value = '';
  });
  transaction.addEventListener('complete', () => {
    showTodos();
  });
  transaction.addEventListener('error', () => console.log('Transaction error'));
}

将值添加到存储后,两种表单都将清除字段,以便用户可以将新项目添加到他们的列表中。我们可以通过调用 showTodos 方法来更新视图,我们将在下一节中看到。

5 检索和显示数据

要检查“保存任务”功能是否正常工作,请在浏览器中打开并使用检查功能。在 Chrome 中,您可以在应用程序选项卡下的存储中看到 IndexedDB。如下图所示,我们创建了一个数据库,并将第一个任务项存储在 todo_tb 对象存储中: IndexedDB完整使用指南

在用户加载页面时显示可用的任务项,并提供一个视图对于之前添加和删除的任务项,我们将创建一个名为 showTodos :

function showTodos() {
  while (todos.firstChild) {
    todos.removeChild(todos.firstChild);
  }
  const objectStore = db.transaction('todo_tb').objectStore('todo_tb');
  objectStore.openCursor().addEventListener('success', e => {

    const pointer = e.target.result;
    if(pointer) {
      const listItem = document.createElement('li');
      const h3 = document.createElement('h3');
      const pg = document.createElement('p');
      listItem.appendChild(h3);
      listItem.appendChild(pg);
      todos.appendChild(listItem);
      h3.textContent = pointer.value.title;
      pg.textContent = pointer.value.body;
      listItem.setAttribute('data-id', pointer.value.id);
      const deleteBtn = document.createElement('button');
      listItem.appendChild(deleteBtn);
      deleteBtn.textContent = 'Remove';
      deleteBtn.addEventListener('click', deleteItem);
      pointer.continue();
    } else {
      if(!todos.firstChild) {
        const listItem = document.createElement('li');
        listItem.textContent = 'No Todo.'
        todos.appendChild(listItem);
      }

      console.log('Todos all shown');
    }
  });
}

的方法,此方法从存储中检索 Todos 项,迭代每个项,并创建一个 A HTML 元素。将项目添加到网页上的列表项 ol,将每个任务项的 id 传递到名为 data-id 的数据属性。稍后,当我们介绍 deleteItem 函数时,当我们需要从内存中删除它时,我们将使用这个唯一的 ID 来标识每个任务。

要在页面加载时获取任务项,请将成功事件监听器 openOrCreateDB 更改为:

openOrCreateDB.addEventListener('success', () => {
  console.log('Successfully opened DB');
  db = openOrCreateDB.result;
  showTodos();
});

6 从数据库中删除数据

最后,让我们测试一下该数据库 DELETE API 并为我们的待办事项列表应用程序创建一个函数 删除

function deleteItem(e) {
  const todoId = Number(e.target.parentNode.getAttribute('data-id'));
  const transaction = db.transaction(['todo_tb'], 'readwrite');
  const objectStore = transaction.objectStore('todo_tb');
  objectStore.delete(todoId);
  transaction.addEventListener('complete', () => {
    e.target.parentNode.parentNode.removeChild(e.target.parentNode);
    alert(`Todo with id of ${todoId} deleted`)
    console.log(`Todo:${todoId} deleted.`);
    if(!todos.firstChild) {
      const listItem = document.createElement('li');
      listItem.textContent = 'No Todo.';
      todos.appendChild(listItem);
    }
  });
  transaction.addEventListener('error', () => console.log('Transaction error'));
}

这将使用唯一的 ID 删除指定的任务项目,并从页面中删除该项目。删除内存中的最后一个任务后,在任务列表位置显示“无任务项”消息。

要确认任务项已从数据库中删除,请继续检查网页并单击“应用程序”选项卡。如您所见,对象存储 todo_tb 现在不包含任何项目: IndexedDB完整使用指南

最终应用程序 Web 如下所示: IndexedDB完整使用指南

7 索引数据库的增量版本

IndexedDB还允许开发人员增加数据库版本。打开数据库时,指定所需的版本号:

window.indexedDB.open('todo_db', 1);

如果数据库不存在,则会使用指定的版本创建数据库。如果数据库已经存在,则检查版本号。

如果调用open方法时指定的版本号高于现有版本,则通过onUpgradeNeeded事件触发版本变更事件。此事件允许您执行数据库架构更改或数据迁移。

需要注意的一点是,删除之前的商品商店以添加新选项,创建新商品也会删除旧商店中的所有其他数据。在升级数据库之前,读取旧内容并将其存储在其他地方。

8 使用索引数据库的缺点

由于 IndexedDB 依赖于客户端的 web 浏览器,因此它通常更适合个人用户或小型应用程序。虽然它可以处理大量数据,但在大型应用程序或多人使用的应用程序中使用IndexedDB 时存在一些问题。

可扩展性限制

IndexedDBWeb 浏览器 中运行,这意味着它受到客户端环境的功能和资源的限制。它可能不太适合需要处理大量并发用户或极高吞吐量的场景。

数据大小限制

不同的网络浏览器对IndexedDB中可以存储的最大数据量设置限制。这些限制因浏览器而异,范围可以从几兆字节到数百兆字节。

了解这些限制并相应地设计您的应用程序非常重要。当数据存储空间耗尽时,您将无法将新数据保存到数据库,因为会引发错误QuotaExceededError

同步挑战

IndexedDB 没有提供内置机制来管理客户端之间的数据同步或处理分布式环境中的冲突。您必须实现自定义同步逻辑来处理这些场景。维护不同应用程序实例之间的数据一致性和同步变得复杂。

因此,对于大型应用或者多人使用的应用,使用服务器端数据库或者云存储方案会更加高效。

9 写在最后

在这篇文章中,我们了解了 IndexedDB web 上的数据库以及如何使用 JavaScript 与其互动存储数据应用程序Web

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门