持久化储存之IndexDB常用方法封装

官方解释:IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。

IndexedDB提供了一套完整的API,包括打开数据库连接,创建数据库对象,增删改查等,然而这些API当中存在部分异步、部分同步的情况,异步接口并非Promise形式,操作起来稍有点复杂,相比localStorage来说,于是我对常用的一些方法进行了二次封装。

创建

创建一个数据库操作对象,并返回一个Object对象
数据库版本默认为: 1

/**
 * 创建一个数据库连接
 * @param {String} dbName 数据库名
 * @param {Number} version 数据库版本
 */
function createIndexDB(dbName, version = 1) {
  if (!dbName) {
    throw new Error('dbName is required.')
  }

  let db

  return {}
}

由于原生的IndexDB操作大部分是属于异步请求事件,则用Promise封装一个公共的方法

const createAsyncRequest = (request, options) => {
  return new Promise((resolve, reject) => {
    request.onsuccess = function (e) {
      res = e.target.result
      resolve(res)
    }

    request.onerror = function (e) {
      reject(new Error(e.target.error))
    }
  })
}

打开

打开数据库,不存在时会默认创建这个数据库,返回Promise

/**
 * 创建一个数据库连接
 * @param {String} dbName 数据库名
 * @param {Number} version 数据库版本
 */
function createIndexDB(dbName, version = 1) {
  if (!dbName) {
    throw new Error('dbName is required.')
  }

  let db

  return {
    open() {
      return new Promise((resolve, reject) => {
        const request = window.indexedDB.open(dbName, version)
        request.onsuccess = function (e) {
          db = e.target.result
          resolve(db)
        }

        request.onerror = function (e) {
          reject(new Error(e.target.error))
        }

        // 数据库创建或升级的时触发
        request.onupgradeneeded = function (e) {
          db = e.target.result
          resolve(db)
        }
      })
    },
  }
}

关闭

关闭数据库

function close() {
  const request = db.open(dbName)
  return createAsyncRequest(request)
}

创建仓库对象

创建仓库数据对象(表) [同步]

function createObjectStore(storeName, options = {}) {
  const _options = {
    keyPath: 'id',
    ...options
  }

  try {
    if (!db.objectStoreNames.contains(storeName)) {
      let objectStore = db.createObjectStore(storeName, _options)
      return objectStore
    } else {
      throw new Error(`The storeName <${storeName}> is exist.`)
    }
  } catch (e) {
    throw new Error(e.target.error)
  }
}

删除仓库对象

删除仓库数据对象(表) [同步]

function deleteObjectStore(storeName) {
  try {
    if (!db.objectStoreNames.contains(storeName)) {
      return db.deleteObjectStore(storeName)
    } else {
      throw new Error(`The storeName <${storeName}> is not exist.`)
    }
  } catch (e) {
    throw new Error(e.target.error)
  }
}

创建索引

基于仓库数据对象创建索引

// 创建索引 [同步]
function createIndex(objectStore, options = {}) {
  const {indexName, keyPath, objectParameters} = options

  try {
    if (objectStore) {
      return objectStore.createIndex(indexName, keyPath, objectParameters) 
    } else {
      throw new Error(`The objectStore is required.`)
    }
  } catch (e) {
    throw new Error(e.target.error)
  }
}

删除索引

基于仓库数据对象删除索引

// 删除索引 [同步]
function deleteIndex(objectStore, indexName) {
  try {
    if (objectStore) {
      return objectStore.deleteIndex(indexName) 
    } else {
      throw new Error(`The objectStore is required.`)
    }
  } catch (e) {
    throw new Error(e.target.error)
  }
}

操作数据对象

由于增删改查数据都需要操作仓库数据对象,则可将其封装成公共方法

function transactionObjectStore(storeName, options) {
  const {model = 'readwrite', oncomplete, onerror} = options

  try {
    const transaction = db.transaction([storeName], model)
    transaction.oncomplete = oncomplete
    transaction.onerror = function(e) {
      onerror && onerror(e)
      throw new Error(e.target.error)
    }

    const objectStore = transaction.objectStore(storeName)
    return objectStore
  } catch (e) {
    throw new Error(e.target.error)
  }
}

基于仓库数据对象插入新数据

function add(storeName, data) {
  let request = transactionObjectStore(storeName).add(data)
  return createAsyncRequest(request)
}

基于仓库数据对象删除数据

function delete(storeName, key) {
  let request = transactionObjectStore(storeName).delete(key)
  return createAsyncRequest(request)
}

基于仓库数据对象更新数据

function put(storeName, data) {
  let request = transactionObjectStore(storeName).put(data)
  return createAsyncRequest(request)
}

基于仓库数据对象查询数据

function get(storeName, key) {
  let request = transactionObjectStore(storeName, {model: 'readonly'}).get(key)
  return createAsyncRequest(request)
}

查-所有

基于仓库数据对象查询所有数据

function getAll(storeName, query, count) {
  let request = transactionObjectStore(storeName).getAll(query, count)
  return createAsyncRequest(request)
}

查-条目数

基于仓库数据对象查询条目数

function count(storeName, query) {
  let request = transactionObjectStore(storeName).count(query)
  return createAsyncRequest(request)
}

代码清单

// util.indexDB.js

/**
 * 创建一个数据库连接
 * @param {Object} options 选项
 */
function createIndexDB(dbName, version = 1) {
  if (!dbName) {
    throw new Error('dbName is required.')
  }

  let db
  const createAsyncRequest = (request, options) => {
    return new Promise((resolve, reject) => {
      request.onsuccess = function (e) {
        res = e.target.result
        resolve(res)
      }

      request.onerror = function (e) {
        reject(new Error(e.target.error))
      }
    })
  }

  return {
    // 打开数据库,不存在时会默认创建
    open() {
      return new Promise((resolve, reject) => {
        const request = window.indexedDB.open(dbName, version)
        request.onsuccess = function (e) {
          db = e.target.result
          resolve(db)
        }

        request.onerror = function (e) {
          reject(new Error(e.target.error))
        }

        // 数据库创建或升级的时触发
        request.onupgradeneeded = function (e) {
          db = e.target.result
          resolve(db)
        }
      })
    },

    // 关闭数据库
    close() {
      const request = db.open(dbName)
      return createAsyncRequest(request)
    },

    // 创建仓库对象(表) [同步]
    createObjectStore(storeName, options = {}) {
      const _options = {
        keyPath: 'id',
        ...options
      }

      try {
        if (!db.objectStoreNames.contains(storeName)) {
          let objectStore = db.createObjectStore(storeName, _options)
          return objectStore
        } else {
          throw new Error(`The storeName <${storeName}> is exist.`)
        }
      } catch (e) {
        throw new Error(e.target.error)
      }
    },

    // 删除仓库对象(表) [同步]
    deleteObjectStore(storeName) {
      try {
        if (!db.objectStoreNames.contains(storeName)) {
          return db.deleteObjectStore(storeName)
        } else {
          throw new Error(`The storeName <${storeName}> is not exist.`)
        }
      } catch (e) {
        throw new Error(e.target.error)
      }
    },

    // 创建索引 [同步]
    createIndex(objectStore, options = {}) {
      const {indexName, keyPath, objectParameters} = options

      try {
        if (objectStore) {
          return objectStore.createIndex(indexName, keyPath, objectParameters) 
        } else {
          throw new Error(`The objectStore is required.`)
        }
      } catch (e) {
        throw new Error(e.target.error)
      }
    },

    // 删除索引 [同步]
    deleteIndex(objectStore, indexName) {
      try {
        if (objectStore) {
          return objectStore.deleteIndex(indexName) 
        } else {
          throw new Error(`The objectStore is required.`)
        }
      } catch (e) {
        throw new Error(e.target.error)
      }
    },

    // 操作数据对象
    transactionObjectStore(storeName, options) {
      const {model = 'readwrite', oncomplete, onerror} = options

      try {
        const transaction = db.transaction([storeName], model)
        transaction.oncomplete = oncomplete
        transaction.onerror = function(e) {
          onerror && onerror(e)
          throw new Error(e.target.error)
        }

        const objectStore = transaction.objectStore(storeName)
        return objectStore
      } catch (e) {
        throw new Error(e.target.error)
      }
    },

    // 插入数据
    add(storeName, data) {
      let request = transactionObjectStore(storeName).add(data)
      return createAsyncRequest(request)
    },

    // 查询数据
    get(storeName, key) {
      let request = transactionObjectStore(storeName, {model: 'readonly'}).get(key)
      return createAsyncRequest(request)
    },

    // 查询数据
    getAll(storeName, query, count) {
      let request = transactionObjectStore(storeName).getAll(query, count)
      return createAsyncRequest(request)
    },

    // 更新数据
    put(storeName, data) {
      let request = transactionObjectStore(storeName).put(data)
      return createAsyncRequest(request)
    },

    // 删除数据
    delete(storeName, key) {
      let request = transactionObjectStore(storeName).delete(key)
      return createAsyncRequest(request)
    },

    // 清除数据
    clear(storeName) {
      let request = transactionObjectStore(storeName).clear()
      return createAsyncRequest(request)
    },

    // 条目数
    count(storeName, query) {
      let request = transactionObjectStore(storeName).count(query)
      return createAsyncRequest(request)
    },
  }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值