Introduction to the

IndexedDB is a database built into the new browsers of the HTML5 specification. For storing data in a browser, you can use cookies or local storage, but these are simpler techniques, and IndexedDB provides a database-like way to store and use data. Data stored in IndexedDB is permanent, not temporary like cookies. IndexedDB provides the ability to query data in both online and offline mode. You can use IndexedDB to store large data.

IndexedDB data is stored as objects, each of which has a key index. Operations in IndexedDB are transactional. An object is stored in an objectStore, which acts as a table in a relational database. IndexedDB can have many objectStores, and objectStores can have many objects in them. Each object can be retrieved with a key value.

IndexedDB vs LocalStorage

IndexedDB and LocalStorage are both used to store data in the browser, but they use different technologies and have different uses, and you need to choose which one to use according to your situation. LocalStorage stores data in key-value mode, but unlike IndexedDB, it does not store data as objects. It stores all the data as strings. If you want LocalStorage to store objects, you need json.stringify () to turn objects into strings, and json.parse () to restore strings to objects. But if you want to store a lot of complex data, this is not a good solution. After all, LocalStorage is designed for small amounts of data, and its API is synchronous.

IndexedDB is great for storing large amounts of data, and its API is called asynchronously. IndexedDB uses indexes to store data, and various database operations are performed in transactions. IndexedDB even supports simple data types. IndexedDB is much more powerful than LocalStorage, but its API is also relatively complex.

For simple data, you should continue to use localStorage, but when you want to store a large amount of data, IndexedDB is obviously more suitable. IndexedDB can provide you with a more complex way to query data.

IndexedDB vs Web SQL

WebSQL is also a technique for storing data in the browser. Unlike IndexedDB, which is more of a NoSQL database, WebSQL is more of a relational database that uses SQL to query data. The W3C no longer supports this technique.

For details, please see: www.w3.org/TR/webdatab…

You should not use this technique in your projects because it is no longer supported.

IndexedDB vs Cookies

Cookies are passed each time HTTP is received and sent, which can consume additional traffic. For example, if you have a 10KB of cookie data and send 10 requests, then a total of 100KB of data will be transferred over the network. Cookies can only be strings. Browsers have limited space to store Cookies, and many users prohibit their use. Therefore, Cookies can only be used to store small amounts of non-critical data.

Browser support for IndexedDB

Different browsers have different implementations of IndexedDB. Normally, we can use window.indexeddb to retrieve the browser’s IndexedDB object. However, for some browsers, instead of using the standard window.indexeddb, a prefixed implementation is used.

Therefore, we usually need to make judgments and transformations in the process of use:

// In the following line, you should include the prefixes of implementations you want to test.
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
// DON'T use "var indexedDB = ..." if you're not in a function.
// Moreover, you may need references to some window.IDB* objects:
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"}; // This line should only be needed if it is needed to support the object's constants for older browsers
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
// (Mozilla has never prefixed these objects, so we don't need window.mozIDB*)
Copy the code

Above we get indexedDB, IDBTransaction, and IDBKeyRange objects from window.

IndexedDB represents the connection to the database. IDBTransaction refers to transaction, while IDBKeyRange refers to fetching data from a specific key range in the database.

However, prefixed implementations are generally unstable, so we generally do not recommend using them in formal environments, so if standard expressions are not supported, an error is reported:

if (! window.indexedDB) { console.log("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available."); }Copy the code

How to get started with IndexedDB

Understanding and use of indexDB

Usage scenarios

The application scenario is discussed in combination with its advantages and disadvantages.

  • Not suitable for large data stores, the browser has a 50M limit on the size of indexDB
  • Not suitable for projects requiring high compatibility
  • Not suitable for storing sensitive data
  • Problems can occur when the user clears the browser cache
  • IndexedDB is restricted by the same origin policy

Utility methods

/**
 * 封装的方法以及用法
    <!-- <script type="module">
    import { openDB,
            addData,
            getDataByKey,
            cursorGetData,
            getDataByIndex,
            cursorGetDataByIndex,
            updateDB,
            deleteDB,
            cursorDelete,
            closeDB,
            deleteDBAll } from './indexedDb.js'
    openDB('myDB', 'one').then(db => {  // 打开 / 创建 Indexed 数据 
      // addData(db, 'one', { id: 1, name: '张三', age: 24 }) // 新增数据
      // addData(db, 'one', { id: 2, name: '李四', age: 30 }) // 新增数据
      // getDataByKey(db, 'one', 1) // 通过主键读取数据
      // cursorGetData(db, 'one') // 通过游标读取数据
      // getDataByIndex(db, 'one','name', '张三') // 通过索引读取数据
      // cursorGetDataByIndex(db, 'one', 'name', '张三') // 通过索引和游标查询记录
      // updateDB(db, 'one', { id: 1, name: '张三', age: 25 }) // 更新数据
      // deleteDB(db, 'one', 2) // 删除数据
      // cursorDelete(db, 'one', 'name', '张三') // 通过索引和游标删除指定的数据
      // closeDB(db) // 关闭数据库
    })
    // deleteDBAll('myDB') // 删除数据库 慎用!!!!!!!!!!
  </script> -->
 * 
 * 打开数据库
 * @param {object} dbName 数据库的名字
 * @param {string} storeName 仓库名称
 * @param {string} version 数据库的版本
 * @return {object} 该函数会返回一个数据库实例
 */
export function openDB(dbName, storeName, version = 1) {
  return new Promise((resolve, reject) => {
    //  兼容浏览器
    var indexedDB =
      window.indexedDB ||
      window.mozIndexedDB ||
      window.webkitIndexedDB ||
      window.msIndexedDB
    let db
    const request = indexedDB.open(dbName, version)
    request.onsuccess = function (event) {
      db = event.target.result // 数据库对象
      console.log('数据库打开成功')
      resolve(db)
    }

    request.onerror = function (event) {
      console.log('数据库打开报错')
    }

    request.onupgradeneeded = function (event) {
      // 数据库创建或升级的时候会触发
      console.log('onupgradeneeded')
      db = event.target.result // 数据库对象
      var objectStore
      if (!db.objectStoreNames.contains(storeName)) {
        objectStore = db.createObjectStore(storeName, { keyPath: 'id' }) // 创建表
        objectStore.createIndex('name', 'name', { unique: false }) // 创建索引 可以让你搜索任意字段
        // objectStore.createIndex('address', 'address', { unique: false })
        // objectStore.createIndex('nameAddr', ['name', 'address'], {
        //  unique: false,
        // })
        // objectStore.createIndex('flag', 'flag', { unique: false })
      }
    }
  })
}

/**
 * 新增数据
 * @param {object} db 数据库实例
 * @param {string} storeName 仓库名称
 * @param {string} data 数据
 */
export function addData(db, storeName, data) {
  var request = db
    .transaction([storeName], 'readwrite') // 事务对象 指定表格名称和操作模式("只读"或"读写")
    .objectStore(storeName) // 仓库对象
    .add(data)

  request.onsuccess = function (event) {
    console.log('数据写入成功')
  }

  request.onerror = function (event) {
    console.log('数据写入失败')
    throw new Error(event.target.error)
  }
}

/**
 * 通过主键读取数据
 * @param {object} db 数据库实例
 * @param {string} storeName 仓库名称
 * @param {string} key 主键值
 */
export function getDataByKey(db, storeName, key) {
  return new Promise((resolve, reject) => {
    var transaction = db.transaction([storeName]) // 事务
    var objectStore = transaction.objectStore(storeName) // 仓库对象
    var request = objectStore.get(key)

    request.onerror = function (event) {
      console.log('事务失败')
    }

    request.onsuccess = function (event) {
      console.log('主键查询结果: ', request.result)
      resolve(request.result)
    }
  })
}

/**
 * 通过游标读取数据
 * @param {object} db 数据库实例
 * @param {string} storeName 仓库名称
 */
export function cursorGetData(db, storeName) {
  let list = []
  var store = db
    .transaction(storeName, 'readwrite') // 事务
    .objectStore(storeName) // 仓库对象
  var request = store.openCursor() // 指针对象
  request.onsuccess = function (e) {
    var cursor = e.target.result
    if (cursor) {
      // 必须要检查
      list.push(cursor.value)
      cursor.continue() // 遍历了存储对象中的所有内容
    } else {
      console.log('游标查询结果:', list)
    }
  }
}

/**
 * 通过索引读取数据
 * @param {object} db 数据库实例
 * @param {string} storeName 仓库名称
 * @param {string} indexName 索引名称
 * @param {string} indexValue 索引值
 */
export function getDataByIndex(db, storeName, indexName, indexValue) {
  var store = db.transaction(storeName, 'readwrite').objectStore(storeName)
  var request = store.index(indexName).get(indexValue)
  request.onerror = function () {
    console.log('事务失败')
  }
  request.onsuccess = function (e) {
    var result = e.target.result
    console.log('索引查询结果:', result)
  }
}

/**
 * 通过索引和游标查询记录
 * @param {object} db 数据库实例
 * @param {string} storeName 仓库名称
 * @param {string} indexName 索引名称
 * @param {string} indexValue 索引值
 */
export function cursorGetDataByIndex(db, storeName, indexName, indexValue) {
  let list = []
  var store = db.transaction(storeName, 'readwrite').objectStore(storeName) // 仓库对象
  var request = store
    .index(indexName) // 索引对象
    .openCursor(IDBKeyRange.only(indexValue)) // 指针对象
  request.onsuccess = function (e) {
    var cursor = e.target.result
    if (cursor) {
      // 必须要检查
      list.push(cursor.value)
      cursor.continue() // 遍历了存储对象中的所有内容
    } else {
      console.log('游标索引查询结果:', list)
    }
  }
  request.onerror = function (e) {}
}

/**
 * 更新数据
 * @param {object} db 数据库实例
 * @param {string} storeName 仓库名称
 * @param {object} data 数据
 */
export function updateDB(db, storeName, data) {
  var request = db
    .transaction([storeName], 'readwrite') // 事务对象
    .objectStore(storeName) // 仓库对象
    .put(data)

  request.onsuccess = function () {
    console.log('数据更新成功')
  }

  request.onerror = function () {
    console.log('数据更新失败')
  }
}

/**
 * 删除数据
 * @param {object} db 数据库实例
 * @param {string} storeName 仓库名称
 * @param {object} id 主键值
 */
export function deleteDB(db, storeName, id) {
  var request = db
    .transaction([storeName], 'readwrite')
    .objectStore(storeName)
    .delete(id)

  request.onsuccess = function () {
    console.log('数据删除成功')
  }

  request.onerror = function () {
    console.log('数据删除失败')
  }
}

/**
 * 通过索引和游标删除指定的数据
 * @param {object} db 数据库实例
 * @param {string} storeName 仓库名称
 * @param {string} indexName 索引名
 * @param {object} indexValue 索引值
 */
export function cursorDelete(db, storeName, indexName, indexValue) {
  var store = db.transaction(storeName, 'readwrite').objectStore(storeName)
  var request = store
    .index(indexName) // 索引对象
    .openCursor(IDBKeyRange.only(indexValue)) // 指针对象
  request.onsuccess = function (e) {
    var cursor = e.target.result
    var deleteRequest
    if (cursor) {
      deleteRequest = cursor.delete() // 请求删除当前项
      deleteRequest.onerror = function () {
        console.log('游标删除该记录失败')
      }
      deleteRequest.onsuccess = function () {
        console.log('游标删除该记录成功')
      }
      cursor.continue()
    }
  }
  request.onerror = function (e) {}
}

/**
 * 关闭数据库
 * @param {object} db 数据库实例
 */
export function closeDB(db) {
  db.close()
  console.log('数据库已关闭')
}

/**
 * 删除数据库
 * @param {object} dbName 数据库名称
 */
export function deleteDBAll(dbName) {
  console.log(dbName)
  let deleteRequest = window.indexedDB.deleteDatabase(dbName)
  deleteRequest.onerror = function (event) {
    console.log('删除失败')
  }
  deleteRequest.onsuccess = function (event) {
    console.log('删除成功')
  }
}
Copy the code