HTML5 — 浏览器数据缓存 — indexedDB

html5

浏览数:67

2019-10-8

IndexedDB是一种可以让你在用户的浏览器内持久化存储数据的方法,为web应用提供了丰富的查询功能,使我们的应用在在线和离线都能正常工作。

由于 IndexedDB 本身的规范还在持续演进中,当前的 IndexedDB 的实现还是使用浏览器前缀。在规范更加稳定之前,浏览器厂商对于标准 IndexedDB API 可能都会有不同的实现。但是一旦大家对规范达成共识的话,厂商就会不带前缀标记地进行实现。实际上一些实现已经移除了浏览器前缀:IE 10,Firefox 16 和 Chrome 24。

如果你希望在仍旧使用前缀的浏览器中测试你的代码, 可以使用下列代码:

window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange

要注意的是使用前缀的实现可能会有问题,或者是实现的并不完整,也可能遵循的还是旧版的规范。因此不建议在生产环境中使用。我们更倾向于明确的不支持某一浏览器,而不是声称支持但是实际运行中却出问题:

function hasIndexedDB () {
   if (!window.indexedDB) {
      return true;
   }
}

打开数据库:

// 打开我们的数据库
var request = window.indexedDB.open("MyTestDatabase");

indexedDB打开数据库的方法如上,必须进行request,indexedDB只有一个open方法,上面的代码表示打开了一个”MyTestDatabase”的数据库,该方法可以接受第二个参数:

// 打开我们的数据库,版本号为1
var request = window.indexedDB.open("MyTestDatabase", 1);

第二个参数的版本号为整数,当前打开的版本号不能比现有的版本号小,否则会报错。

几乎所有我们产生的请求我们在处理的时候首先要做的就是添加成功和失败处理函数:

var db;
request.onerror = function(event) { // Do something with request.errorCode! }; request.onsuccess = function(event) {
  db = event.target.result; // Do something with request.result! };

request还有一个回掉方法:

request.onupgradeneeded = function(event) {
  var _db = event.target.result;
  // Do something with request.result!
};

onupgradeneeded方法是只有在版本号升级的情况下才会执行(如果当前版本号为1,当我们在打开open(storeName, 2)时,onupgradeneeded就会执行)。

下面是整个数据库的操作流程:

当我们创建一个新的数据表时,我们首先要在onupgradeneeded方法中创建表:

// 只有在onupgradeneeded方法中有效
var createObjectStore = function (db, storeName) { if (!db.objectStoreNames.contains(storeName)) { db.createObjectStore(storeName, { keyPath: 'id', autoIncrement: true }) console.log("createObjectStore:" + storeName + ",成功!") } }

删除表:

// 删除Store(在onupgradeneeded里调用)
deleteObjectStore (db, storeName) {
    console.log('deleteObjectStore')
    if (db.objectStoreNames.contains(storeName)) {
      db.deleteObjectStore(storeName)
      console.log("deleteObjectStore:" + storeName + ",成功!")
    }
}

表中添加数据:

var students: [
        { id: 1001, name: "Byron", age: 24 }, 
        { id: 1002, name: "Frank", age: 30 }, 
        { id: 1003, name: "Aaron", age: 26 }, 
        { id: 1004, name: "Casper", age: 26 }
]
// 添加数据方法 在onsuccess中执行
var addData = function (db, storeName) {
    console.log('addData success')
    let transaction = db.transaction(storeName, 'readwrite')
    let store = transaction.objectStore(storeName)
    let request = null

    for (let i = 0; i < students.length; i++) {
      request = store.add(tstudents[i])
      request.onerror = function () {
        console.error('数据库已有该数据!')
      } 
      request.onsuccess = function () {
        console.log('添加成功')
      }
    }
}

注意,在执行addData方法的时候,要确保已执行createObjectStore方法,否则会报错。添加完之后浏览器显示:

查询数据:

  // 查询数据(根据关键词keyValue)
  var getDataByKey = function (db, storeName, keyValue) {
    let transaction = db.transaction(storeName, 'readonly')
    let store = transaction.objectStore(storeName)

    let request = store.get(keyValue)
    request.onsuccess = function (e) {
      let result = e.target.result
      console.log(result)
    }
  }

 更新数据:

  // 更新数据
  var updateDataByKey = function (db, storeName, keyValue) {
    let transaction = db.transaction(storeName, 'readwrite')
    let store = transaction.objectStore(storeName)
    let request = store.get(keyValue)
    request.onsuccess = function (e) {
      let student = e.target.result
      student.age = 35
      store.put(student)
      console.log(student)
    }
  }

删除数据:

  // 删除数据
  var deleteDataByKey = function (db, storeName, keyValue) {
    let transaction = db.transaction(storeName, 'readwrite')
    let store = transaction.objectStore(storeName)
    let result = store.delete(keyValue)
    result.onsuccess = function () {
      console.log('删除成功')
    }
    result.onerror = function () {
      console.log('删除失败')
    }
  }

清空表:

  // 清空store
  var clearObjectStore = function (db, storeName) {
    let transaction = db.transaction(storeName, 'readwrite')
    let store = transaction.objectStore(storeName)
    let request = store.clear()
    request.onsuccess = function () {
      console.log('清空成功')
    }
    request.onerror = function () {
      console.log('清空失败')
    }
  }

关闭数据库:

  // 关闭database
  var closeIDB = function (db) {
    db.close()
    console.log('关闭')
  }

删除数据库:

  // 删除database
  var deleteIDB = function (db) {
    console.log('删除')
    window.indexedDB.deleteDatabase(db)
  }

新增表(带索引):

  // 新增Store--带索引(在onupgradeneeded里调用)
  var createObjectStoreWidthIndex = function (db, storeName) {
    if (!db.objectStoreNames.contains(storeName)) {
      let store = db.createObjectStore(storeName, {
        keyPath: 'id'
      })
      store.createIndex('nameIndex', 'name', {
        unique: true
      })
      store.createIndex('ageIndex', 'age', {
        unique: false
      })
      console.log("createObjectStore:" + storeName + ",成功!")
    }
  }

成功之后浏览器端显示:

获取数据的方法:

  // 获取数据(根据索引)
  var getDataByIndex = function (db, storeName) {
    let transaction = db.transaction(storeName, 'readonly')
    let store = transaction.objectStore(storeName)
    let index = store.index('nameIndex')
    index.get('Byron').onsuccess = function (e) {
      let student = e.target.result
      console.log(student)
    }
  }
  // 使用游标
  var fetchStoreByCursor = function (db, storeName) {
    let transaction = db.transaction(storeName)
    let store = transaction.objectStore(storeName)
    let request = store.openCursor() // 查询全部
    request.onsuccess = function (e) {
      let cursor = e.target.result
      if (cursor) {
        let student = cursor.value
        console.log(student)
        cursor.continue()
      }
    }
  }
  // 索引与游标结合
  var getDataByMultiple = function (db, storeName) {
    // 指定游标范围
    // IDBKeyRange.only(value):只获取指定数据
    // IDBKeyRange.lowerBound(value,isOpen):获取比value大的数据(isOpen: true不包含value, false包含value)
    // IDBKeyRange.upperBound(value,isOpen):获取比value小的数据(isOpen: true不包含value, false包含value)
    // IDBKeyRange.bound(value1,value2,isOpen1,isOpen2)
    let transaction = db.transaction(storeName)
    let store = transaction.objectStore(storeName)
    let index = store.index('ageIndex')
    index.openCursor(IDBKeyRange.bound(24, 30, true, true)).onsuccess = function (e) {
      let cursor = e.target.result
      if (cursor) {
        let s = cursor.value
        console.log(s)
        cursor.continue()
      }
    }
  }

如果我们需要手动更新版本,我们先要将indexedDB关闭,然后再打开新版本的数据库:

  var updataVersion = function (db, storeName, version) {
    closeIDB(db)
    console.log('更新版本', storeName, version)
    openIDB(storeName, version)
  }

 

作者:前端杂货