IndexedDB 和在浏览器中存储数据的快速但完整的指南

IndexedDB简介

IndexedDB 是多年来引入浏览器的存储功能之一。
它是一种键/值存储(一种 noSQL 数据库),被认为是在浏览器中存储数据的最终解决方案

它是一个异步 API,这意味着执行昂贵的操作不会阻塞 UI 线程,从而为用户提供草率的体验。它可以存储无限量的数据,尽管一旦超过某个阈值,用户就会被提示给站点更高的限制。

所有现代浏览器都支持它。

它支持事务、版本控制并提供良好的性能。

在浏览器中我们也可以使用:

  • Cookies:可以托管非常少量的字符串
  • Web 存储(或 DOM 存储),一个通常标识 localStorage 和 sessionStorage 的术语,这两个键/值存储。sessionStorage,不保留数据,会话结束时清空,localStorage跨会话保留数据

本地/会话存储的缺点是限制在较小(且不一致)的大小,浏览器实现为每个站点提供 2MB 到 10MB 的空间。

过去我们也有Web SQL,它是 SQLite 的包装器,但现在一些现代浏览器已弃用和不支持它,它从未成为公认的标准,因此不应该使用它,尽管 83% 的用户在他们的用户上使用了这项技术根据 Can I Use的设备。

虽然您可以在技术上为每个站点创建多个数据库,但您通常创建一个数据库,并且在该数据库中您可以创建多个对象存储

数据库对域来说是私有的,因此任何其他站点都无法访问另一个网站 IndexedDB 存储。

每个商店通常包含一组东西,可以是

  • 字符串
  • 数字
  • 对象
  • 数组
  • 日期

例如,您可能有一个包含帖子的商店,另一个包含评论的商店。

商店包含许多具有唯一键的项目,该键表示可以识别对象的方式。

您可以通过执行添加、编辑和删除操作以及迭代它们包含的项目来使用事务来更改这些存储。

自从 ES6 中出现Promises以及随后 API 转向使用 Promise 以来,IndexedDB API 似乎有点过时了。

虽然它没有任何问题,但在我将解释的所有示例中,我将使用 Jake Archibald 的IndexedDB Promised Library,它是 IndexedDB API 之上的一个小层,使其更易于使用。

该库还用于 Google Developers 网站上有关 IndexedDB 的所有示例

创建 IndexedDB 数据库

最简单的方法是使用unpkg,将其添加到页眉中:

<script type="module">
import { openDB, deleteDB } from 'https://unpkg.com/idb?module'
</script>

在使用 IndexedDB API 之前,请始终确保检查浏览器中的支持,即使它广泛可用,但您永远不知道用户正在使用哪个浏览器:

(() => {
  'use strict'

  if (!('indexedDB' in window)) {
    console.warn('IndexedDB not supported')
    return
  }

  //...IndexedDB code
})()

如何创建数据库

使用openDB()

(async () => {
  //...

  const dbName = 'mydbname'
  const storeName = 'store1'
  const version = 1 //versions start at 1

  const db = await openDB(dbName, version, {
    upgrade(db, oldVersion, newVersion, transaction) {
      const store = db.createObjectStore(storeName)
    }
  })
})()

前 2 个参数是数据库名称和版本。第三个参数是可选的,它是一个对象,它包含一个仅在版本号高于当前安装的数据库版本时才调用的函数。在函数体中,您可以升级数据库的结构(存储和索引)。

将数据添加到商店

创建商店时添加数据,初始化它

您使用对象存储的方法,但首先我们需要一个对它的引用,我们可以在创建它时put从中获取。db.createObjectStore()

使用put时,值是第一个参数,键是第二个。这是因为如果您keyPath在创建对象存储时指定,则无需在每次 put() 请求时输入键名,只需写入值即可。

store0一旦我们创建它就会填充它:

(async () => {
  //...
  const dbName = 'mydbname'
  const storeName = 'store0'
  const version = 1

  const db = await openDB(dbName, version,{
    upgrade(db, oldVersion, newVersion, transaction) {
      const store = db.createObjectStore(storeName)
      store.put('Hello world!', 'Hello')
    }
  })
})()

在已创建商店时添加数据,使用事务

要在以后添加项目,您需要创建一个读/写事务,以确保数据库完整性(如果操作失败,事务中的所有操作都将回滚,并且状态会返回到已知状态)。

为此,使用对dbPromise调用时获得的对象的引用openDB,然后运行:

(async () => {
  //...
  const dbName = 'mydbname'
  const storeName = 'store0'
  const version = 1

  const db = await openDB(/* ... */)

  const tx = db.transaction(storeName, 'readwrite')
  const store = await tx.objectStore(storeName)

  const val = 'hey!'
  const key = 'Hello again'
  const value = await store.put(val, key)
  await tx.done
})()

从商店获取数据

从商店获取一件商品:get()

const key = 'Hello again'
const item = await db.transaction(storeName).objectStore(storeName).get(key)

从商店获取所有物品:getAll()

获取存储的所有密钥

const items = await db.transaction(storeName).objectStore(storeName).getAllKeys()

获取所有存储的值

const items = await db.transaction(storeName).objectStore(storeName).getAll()

从 IndexedDB 中删除数据

删除数据库、对象存储和数据

删除整个 IndexedDB 数据库

const dbName = 'mydbname'
await deleteDB(dbName)

删除对象存储中的数据

我们使用事务:

(async () => {
  //...

  const dbName = 'mydbname'
  const storeName = 'store1'
  const version = 1

  const db = await openDB(dbName, version, {
    upgrade(db, oldVersion, newVersion, transaction) {
      const store = db.createObjectStore(storeName)
    }
  })

  const tx = await db.transaction(storeName, 'readwrite')
  const store = await tx.objectStore(storeName)

  const key = 'Hello again'
  await store.delete(key)
  await tx.done
})()

从以前版本的数据库迁移

openDB()函数的第三个(可选)参数是一个对象,该对象可以包含仅当版本号高于当前安装的数据库版本时才调用upgrade的函数。在该函数体中,您可以升级数据库的结构(存储和索引):

const name = 'mydbname'
const version = 1
openDB(name, version, {
  upgrade(db, oldVersion, newVersion, transaction) {
    console.log(oldVersion)
  }
})

在这个回调中,您可以查看用户从哪个版本更新,并进行相应的操作。

您可以使用此语法从以前的数据库版本执行迁移

(async () => {
  //...
  const dbName = 'mydbname'
  const storeName = 'store0'
  const version = 1

  const db = await openDB(dbName, version, {
    upgrade(db, oldVersion, newVersion, transaction) {
      switch (oldVersion) {
        case 0: // no db created before
          // a store introduced in version 1
          db.createObjectStore('store1')
        case 1:
          // a new store in version 2
          db.createObjectStore('store2', { keyPath: 'name' })
      }
      db.createObjectStore(storeName)
    }
  })
})()

唯一键

createObjectStore()如您所见,case 1接受第二个参数,该参数指示数据库的索引键。这在存储对象时非常有用:put()调用不需要第二个参数,但可以只取值(一个对象),键将映射到具有该名称的对象属性。

索引为您提供了一种稍后通过该特定键检索值的方法,并且它必须是唯一的(每个项目必须具有不同的键)

可以将键设置为自动递增,因此您无需在客户端代码上跟踪它:

db.createObjectStore('notes', { autoIncrement: true })

如果您的值尚未包含唯一键(例如,如果您收集没有关联名称的电子邮件地址),请使用自动递增。

检查商店是否存在

objectStoreNames()您可以通过调用该方法检查对象存储是否已存在:

const storeName = 'store1'

if (!db.objectStoreNames.contains(storeName)) {
  db.createObjectStore(storeName)
}

从 IndexedDB 中删除

删除数据库、对象存储和数据

删除数据库

await deleteDB('mydb')

删除对象存储

对象存储只能在打开数据库时在回调中删除,并且仅当您指定的版本高于当前安装的版本时才会调用该回调:

const db = await openDB('dogsdb', 2, {
  upgrade(db, oldVersion, newVersion, transaction) {
    switch (oldVersion) {
      case 0: // no db created before
        // a store introduced in version 1
        db.createObjectStore('store1')
      case 1:
        // delete the old store in version 2, create a new one
        db.deleteObjectStore('store1')
        db.createObjectStore('store2')
    }
  }
})

要删除对象存储中的数据,请使用事务

const key = 232 //a random key

const db = await openDB(/*...*/)
const tx = await db.transaction('store', 'readwrite')
const store = await tx.objectStore('store')
await store.delete(key)
await tx.complete

还有更多!

这些只是基础知识。我没有谈论游标和更高级的东西。IndexedDB 还有更多内容,但我希望这能给您一个良好的开端。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值