IndexDB快速入门
IndexDB是适用于浏览器的文档数据库,它有以下特点:
- 兼容所有现代的浏览器
- 支持事务以及版本控制
- 支持无限数量的数据。很多浏览器会限定localStorage或者sessionStorage的存储空间为2M到10M
- IndexDB是异步的API,它不会阻塞浏览器UI的渲染
下面介绍下它的使用。
安装依赖包idb
需要把idb的js库添加到依赖。有几种方式添加idb到依赖。
yarn
yarn add idb
npm
npm install idb --save
安装后可以使用webpack等工具把它添加到页面,或者在页面直接引用
<script src="./node_modules/idb/lib/idb.js"></script>
在开始使用indexdb前,建议先检测浏览器是否支持indexdb。如下:
(() => {
  'use strict'
  if (!('indexedDB' in window)) {
    console.warn('IndexedDB not supported')
    return
  }
//...IndexedDB code
})()
创建IndexDB数据库
使用idb.open()创建indexdb数据库,如下:
const name = 'mydbname' 
const version = 1 //版本 
idb.open(name, version, upgradeDb => {})
idb.open()的第三个参数是可选的,它是用于升级已经安装的indexdb,只有在version大于已经安装的indexdb时才会调用。所以我们的表结构发生变化,就可以通过升级版本号,然后再回调函数upgradeDb里做升级。
创建对象存储
indexDB使用以下语法来创建对象存储:
db.createObjectStore('storeName', options)
其中第一个参数为对象的存储名,第二个参数为选项,可选。
示例:
const dbPromise = idb.open('mydb', 1, (upgradeDB) => {
  upgradeDB.createObjectStore('store1')
})
.then(db => console.log('success'))
如果之前已经安装了一个旧版本的indexdb,那么你可以在升级回调里把一个新的对象存储添加进去。
const dbPromise = idb.open('mydb', 3, (upgradeDB) => {
  switch (upgradeDB.oldVersion) {
    case 0: //旧版本为0时,表示是一个新的indexdb
      //在版本1创建store1
      upgradeDB.createObjectStore('store1')
    case 1:
      // 版本2新增store1
      upgradeDB.createObjectStore('store2', { keyPath: 'name' })
  }
})
.then(db => console.log('success'))
createObjectStore的第二个参数里的选项keyPath,是用来设置索引键,指定为索引的键需要时唯一的,即所有数据项此键的值是不同的。
键可以设置为自增,你不需要去指定它,IndexedDB会为自动创建它:
upgradeDb.createObjectStore('notes', { autoIncrement: true })
合起来指定一个索引键,并设置为自增:
upgradeDb.createObjectStore('notes', {
  keyPath: 'id',
  autoIncrement: true
})
索引
索引可以在idb.open的升级回调函数里添加,如下:
const dbPromise = idb.open('dogsdb', 1, (upgradeDB) => {
  const dogs = upgradeDB.createObjectStore('dogs')
  dogs.createIndex('nameIndex', 'name', { unique: false })
})
createIndex三个参数:
- indexName:第一个参数为索引名
- field:第二个参数为索引对应的属性
- options:选项
在第三个参数选项unique,用来指示所以是否是唯一的。
除了在新建objectStore时添加索引,也可以在已经创建好的ojbectStore补充添加索引,如下:
const dbPromise = idb.open('dogsdb', 1, (upgradeDB) => {
  const dogs = upgradeDB.transaction.objectStore('dogs')
  dogs.createIndex('name', 'name', { unique: false })
})
其中upgradDb.transation.objectStore()用来获取之前已经创建的objectStore。
检查Store是否已存在
升级数据库结构,特别是创建ObjectStore,常常需要判断Store是否已经创建了。可以使用objectStoreNames来获取所有的objectStore的名称列表。
if (!upgradeDb.objectStoreNames.contains('store3')) {
  upgradeDb.createObjectStore('store3')
}
IndexDB的删除操作
删除数据库
使用idb.delete()来删除数据库,如下:
idb.delete('mydb').then(() => console.log('done'))
删除objectStore
删除objectStore的操作只能在idb.open()的升级回调里执行。如之前所说,idb.open()的升级回调只有在version大于已经安装的数据库版本才会调用。
const dbPromise = idb.open('dogsdb', 2, (upgradeDB) => {
  upgradeDB.deleteObjectStore('old_store')
})
使用事务删除object store里的数据项:
const key = 232
dbPromise.then((db) => {
  const tx = db.transaction('store', 'readwrite')
  const store = tx.objectStore('store')
  store.delete(key)
  return tx.complete
})
.then(() => {
  console.log('Item deleted')
})
新增/更新数据
添加数据项到objectStore,可以使用objectStore的put(val,key)方法,需要注意的是第一个参数为值,第二个参数为键。
在使用put方法前,先要获取objectStore对象。获取方法:
db.transaction().objectStore()
示例:
const dbPromise = idb.open("mydb",1);
dbPromise.then((db) => {
  const val = 'hey!'
  const key = 'Hello again'
  const tx = db.transaction('store1', 'readwrite')
  tx.objectStore('store1').put(val, key)
  return tx.complete
})
.then(() => {
  console.log('Transaction complete')
})
.catch(() => {
  console.log('Transaction failed')
})
尽管indexDB提供了add()方法,但put()方法除了添加功能外,同时也是可以为更新操作,所有put是比较常用的新增或更新数据项的方法。
查询数据
1、使用get获取store里的指定的数据项
dbPromise.then(db => db.transaction('objs')
                       .objectStore('objs')
                       .get(123456))
.then(obj => console.log(obj))
2、使用getAll()获取所有的数据项
dbPromise.then(db => db.transaction('store1')
                       .objectStore('store1')
                       .getAll())
.then(objects => console.log(objects))
3、通过openCursor()使用游标迭代数据
dbPromise.then((db) => {
  const tx = db.transaction('store', 'readonly')
  const store = tx.objectStore('store')
  return store.openCursor()
})
.then(function logItems(cursor) {
  if (!cursor) { return }
  console.log('cursor is at: ', cursor.key)
  for (const field in cursor.value) {
    console.log(cursor.value[field])
  }
  return cursor.continue().then(logItems)
})
.then(() => {
  console.log('done!')
})
4、使用游标和边界来迭代数据项的子集
const searchItems = (lower, upper) => {
  if (lower === '' && upper === '') { return }
  let range
  if (lower !== '' && upper !== '') {
    range = IDBKeyRange.bound(lower, upper)
  } else if (lower === '') {
    range = IDBKeyRange.upperBound(upper)
  } else {
    range = IDBKeyRange.lowerBound(lower)
  }
  dbPromise.then((db) => {
    const tx = db.transaction(['dogs'], 'readonly')
    const store = tx.objectStore('dogs')
    const index = store.index('age')
    return index.openCursor(range)
  })
  .then(function showRange(cursor) {
    if (!cursor) { return }
    console.log('cursor is at:', cursor.key)
    for (const field in cursor.value) {
      console.log(cursor.value[field])
    }
    return cursor.continue().then(showRange)
  })
  .then(() => {
    console.log('done!')
  })
}
searchDogsBetweenAges(3, 10)
 
             
             
             
             
            