JavaScript笔记之indexedDB的轻量化使用(增删改查)

前些日子尝试使用 HTML5indexedDB,发现标准提出来的非关系型数据库真的很难用,根据自己理解基于 indexedDB 封装了一个轻量级的数据库管理类,能够快速的建表、存数据。

1.需求分析

介于 indexedDB 不人性化的事务操作,以及神奇的建表逻辑(只能通过升级数据库,在升级事件内建表!),考虑自己实际需求做了以下的取舍:

  1. 因为轻量级原因,我只需要建多张表而不需要建数据库,因此全局只要维护一个数据库实例即可;
  2. 因其离谱的建表逻辑(也有可能我没把握住),通过多次尝试,最终选择在需要建表的时候主动升级数据库;
  3. indexedDB 按索引查询方法过于繁琐(需要根据数据设置索引),因此通过 cursor 遍历、人为找到要查询的数据,这样的好处是对 SDK 调用友好。

2.数据库管理对象接口封装

创建原型对象,并初始化相关变量:

// 可以参见之前的博客
import promise from 'promise.js'

/*
* 数据半持久化存储
* 注: 利用 IndexDB 做数据缓存
*/
let MircoDB = function () {
  // 初始化数据库名
  this._db_name = '_MICRO_DB'

  // 定义数据库
  this._micro_db = undefined

  // 数据库版本
  this.version = 0

  // 获取 indexedDB 管理对象
  this._indexedDB = undefined
}

初始化数据库,并打开:

/*
* 数据库初始化接口
* 返回 Promise 对象
*/
MircoDB.prototype.init = function () {
  let deffer = _promise.deffer()

  // 调用初始化函数
  this._init(deffer)

  return deffer.promise
}

/*
* [内部函数
* 初始化
*/
MircoDB.prototype._init = function (deffer) {
  let request

  // 初始化
  this._indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB

  // 打开数据库
  request = this._indexedDB.open(this._db_name)

  // 错误监听
  request.onerror = (event) => {
    // 抛出异常
    deffer.reject(new Error(error.DB_OPEN_ERROR))
  }

  // 正确打开监听
  request.onsuccess = (event) => {
    // 绑定数据库
    this._micro_db = event.target.result
    // 记录版本号
    this.version = this._micro_db.version
    // 返回结果
    deffer.resolve(true)
  }
}

建表,这里也有比较坑的地方,建表后需要重新赋值数据对象,不然数据库对象会丢失:

/*
* 创建表
* 注: 如果存在,那么打开表;反之,创建表
* 创建执行事件,如果数据库没打开,就执行。那么直接存储到对应的 TODO 数组内,在打开后执行相应的执行函数。
* 参数 tableName: 表名
* 参数 keys: 搜索索引值(数组),如['name', 'id']
*/
MircoDB.prototype.createTable = function (tableName) {
  let deffer = _promise.deffer()
  let request

  // 如果需要新建数据库,那么放到队列里
  if (!this._micro_db.objectStoreNames.contains(tableName)) {
    // 打开数据库
    this.version++
    this._micro_db.close()
    request = this._indexedDB.open(this._db_name, this.version)

    // 错误监听
   request.onerror = (event) => {
      deffer.reject(new Error(error.DB_OPEN_ERROR))
    }

    request.onupgradeneeded = function (event) {
      this._micro_db = event.target.result
      this._micro_db.createObjectStore(tableName, { keyPath: '_uuid' })
    }

    request.onsuccess = (event) => {
      this._micro_db = event.target.result
      this.version = this._micro_db.version
      deffer.resolve(true)
    }
  } else {
    deffer.resolve(true)
  }

  return deffer.promise
}

增加一条数据(数据对象类型不限):

/*
* 增加数据
*/
MircoDB.prototype.add = function (tableName, object) {
  let deffer = this._gm._internal._promise.deffer()
  let uuid = utils.createUUID(8) // 创建唯一标识,可见仓库代码,也可以自行实现
  let request

  // 添加主键
  object._uuid = uuid

  // 发起请求
  request = this._micro_db.transaction([tableName], 'readwrite')
    .objectStore(tableName)
    .add(object)

  // 成功监听
  request.onsuccess = function (event) {
    // 返回唯一标识
    deffer.resolve(uuid)
  }

  // 错误监听
  request.onerror = function (event) {
    deffer.reject(new Error(error.TABLE_HANDLE_ERROR))
  }

  return deffer.promise
}

删除一条数据,根据 uuid 删除(目前通过增加语句和查询语句返回 uuid,降低复杂度):

/*
* 删除数据
*/
MircoDB.prototype.delete = function (tableName, uuid) {
  let deffer = _promise.deffer()
  let request = this._micro_db.transaction([tableName], 'readwrite')
    .objectStore(tableName)
    .delete(uuid)

  // 成功监听
  request.onsuccess = function (event) {
    deffer.resolve(true)
  }

  // 错误监听
  request.onerror = function (event) {
    deffer.reject(new Error(error.TABLE_HANDLE_ERROR))
  }

  return deffer.promise
}

修改数据:

/*
* 修改数据
* 数据必须包含主键
*/
MircoDB.prototype.update = function (tableName, data) {
  let deffer = _promise.deffer()
  let request = this._micro_db.transaction([tableName], 'readwrite')
    .objectStore(tableName)
    .put(data)

  // 成功监听
  request.onsuccess = function (event) {
    deffer.resolve(true)
  }

  // 错误监听
  request.onerror = function (event) {
    deffer.reject(new Error(error.TABLE_HANDLE_ERROR))
  }

  return deffer.promise
}

查询数据,因为用 cursor(数据库查询指针)的原因,因此查询效率上可能不如索引快,优点是对用户友好:

/*
* 查询数据
*/
MircoDB.prototype.query = function (tableName, queryObj) {
  let deffer = _promise.deffer()
  let request = this._micro_db.transaction([tableName], 'readonly')
    .objectStore(tableName)
    .openCursor()
  let result = []

  // 错误监听
  request.onerror = function (event) {
    deffer.reject(new Error(error.TABLE_HANDLE_ERROR))
  }

  // 成功监听
  request.onsuccess = function (event) {
    let cursor = event.target.result

    if (cursor) {
      let tag = false

      // 循环找到匹配的数据
      for (let key in queryObj) {
        if (cursor.value[key] === queryObj[key]) {
          continue
        } else {
          tag = true
          break
        }
      }

      // 判断是否键值全部匹配
      if (!tag) {
        result.push(cursor.value)
      }

      cursor.continue()
    } else {
      deffer.resolve(result)
    }
  }

  return deffer.promise
}

读取所有数据:

/*
* 读取所有数据
*/
MircoDB.prototype.queryAll = function (tableName) {
  let deffer = _promise.deffer()
  let request = this._micro_db.transaction(tableName, 'readonly')
    .objectStore(tableName)
    .openCursor()
  let result = []

  // 成功监听
  request.onsuccess = function (event) {
    let cursor = event.target.result

    if (cursor) {
      result.push(cursor.value)
      cursor.continue()
    } else {
      deffer.resolve(result)
    }
  }

  // 错误监听
  request.onerror = function (event) {
    deffer.reject(new Error(error.TABLE_HANDLE_ERROR))
  }

  return deffer.promise
}

清空表数据:

/*
* 清空表数据
*/
MircoDB.prototype.clear = function (tableName) {
  let deffer = _promise.deffer()
  let request = this._micro_db.transaction([tableName], 'readwrite')
    .objectStore(tableName)
    .clear()

  // 错误监听
  request.onerror = function (event) {
    deffer.reject(new Error(error.TABLE_HANDLE_ERROR))
  }

  // 成功监听
  request.onsuccess = function (event) {
    deffer.resolve(true)
  }

  return deffer.promise
}

删除表:

/*
* 删除表
*/
MircoDB.prototype.removeTable = function (tableName) {
  let deffer = _promise.deffer()
  let request

  // 如果需要新建数据库,那么放到队列里
  if (this._micro_db.objectStoreNames.contains(tableName)) {
    // 打开数据库
    this.version++
    this._micro_db.close()
    request = this._indexedDB.open(this._db_name, this.version)

    // 错误监听
    request.onerror = (event) => {
      deffer.reject(new Error(error.TABLE_HANDLE_ERROR))
    }

    request.onupgradeneeded = function (event) {
      this._micro_db = event.target.result
      // 删除表名
      this._micro_db.deleteObjectStore(tableName)
      deffer.resolve(true)
    }

    request.onsuccess = (event) => {
      this._micro_db = event.target.result
      this.version = this._micro_db.version
    }
  }

  return deffer.promise
}

3.具体使用

// 创建实例
let _mircodb = new MicroDB()

// 初始化数据库
_microdb.init()
  .then(() => {
    // 创建表
    return _microdb.createTable('my_table') // true
  })
  .then(() => {
    // 插入数据
    return _microdb.add('my_table', {
      val1: 123,
      val2: '123',
      str: 'hello, world'
    })
  })
  .then((uuid) => {
    console.log(uuid) // fde34sd4 唯一标识
    // 插入数据
    return _microdb.update('my_table', {
      _uuid: 'fde34sd4',
      val1: 234,
      val2: '345',
      str: 'hello, world'
    })
  })
  .then(() => {
    // 查询结果
    return _microdb.query('my_table', { val1: 234 })
  })
  .then((result) => {
    console.log(result) // [{ _uuid: 'fde34sd4', val1: 234, val2: '345', str: 'hello, world' }]
  })
  .catch((err) => {
    console.log(err.message)
  })

以上是我在 indexedDB 疯狂踩坑后选用的折中解决方案,大家如果有更好的方案,可以讨论。

注:示例代码可参见 个人前端知识库


created by @SpiderWang
转载请注明作者及链接

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: IndexedDB 是一种浏览器内置的 NoSQL 数据库,允许您在浏览器中存储和检索数据。下面是一个基本的 IndexedDB 示例: ```javascript // 打开 IndexedDB 数据库 var request = window.indexedDB.open("myDatabase", 1); // 处理成功和失败事件 request.onerror = function(event) { console.log("Database error: " + event.target.errorCode); }; request.onsuccess = function(event) { console.log("Database opened successfully"); var db = event.target.result; // 添加数据数据库 var transaction = db.transaction(["customers"], "readwrite"); var objectStore = transaction.objectStore("customers"); var customer = { name: "John", email: "[email protected]" }; var request = objectStore.add(customer); request.onsuccess = function(event) { console.log("Customer added to database"); }; // 从数据库中检索数据 var transaction = db.transaction(["customers"], "readonly"); var objectStore = transaction.objectStore("customers"); var request = objectStore.get(1); request.onerror = function(event) { console.log("Error retrieving customer"); }; request.onsuccess = function(event) { var customer = event.target.result; console.log("Retrieved customer: " + customer.name); }; }; // 创建数据库架构 request.onupgradeneeded = function(event) { var db = event.target.result; var objectStore = db.createObjectStore("customers", { keyPath: "id", autoIncrement: true }); objectStore.createIndex("name", "name", { unique: false }); objectStore.createIndex("email", "email", { unique: true }); }; ``` 这段代码会创建一个名为 "myDatabase" 的 IndexedDB 数据库,其中包含一个名为 "customers" 的对象仓库,用于存储客户数据。该代码还演示了如何向数据库添加数据、从数据库检索数据以及如何创建对象仓库和索引。 ### 回答2: IndexedDB 是一种在 web 浏览器中使用的客户端存储数据库。它可以用于存储大量结构化数据,并且能够在离线状态下进行访问。 一个使用 IndexedDB 的实例可以是一个在线笔记应用。在这个应用中,用户可以创建、编辑和删除笔记使用 IndexedDB,应用可以将这些笔记存储在本地,以便用户在断网或者关闭浏览器后仍然可以访问。 在这个应用中,首先需要创建一个数据库,用于存储笔记数据。然后,可以创建一个 object store,用于存储每一条笔记数据。每一条笔记可以由一个对象表示,其中包含标题、内容和日期等属性。 当用户创建新的笔记时,应用会将该笔记数据添加到 object store 中。当用户编辑或者删除笔记时,应用会相应地更新或者删除 object store 中对应的数据。 当用户重新打开应用时,可以从 IndexedDB 中获取存储的笔记数据,并在界面上展示出来。用户可以通过界面进行编辑,应用会即时地更新 IndexedDB 中的数据。 除了基本的增删改查操作,IndexedDB 还提供了强大的查询功能。通过使用索引,可以高效地搜索和过滤数据。例如,可以根据标题关键字进行搜索,并返回包含该关键字的所有笔记。 总而言之,IndexedDB 提供了一种方便可靠的方式来在 web 浏览器中存储大量结构化数据。通过使用它,可以实现很多实用的应用,如在线笔记应用等。 ### 回答3: IndexedDB 是 HTML5 标准中的一种客户端数据库,可以在浏览器中存储和操作大量的结构化数据。下面是一个使用 IndexedDB 的示例: 首先,在 JavaScript 中创建一个 IndexedDB 数据库,并指定数据库的名称和版本号: ```javascript let request = indexedDB.open('myDatabase', 1); ``` 然后,在打开数据库成功的回调函数中创建一个对象存储空间(类似于表): ```javascript request.onsuccess = (event) => { let db = event.target.result; let objectStore = db.createObjectStore('myObjectStore', { keyPath: 'id' }); }; ``` 现在,可以向对象存储空间中添加数据项: ```javascript request.onsuccess = (event) => { let db = event.target.result; let transaction = db.transaction('myObjectStore', 'readwrite'); let objectStore = transaction.objectStore('myObjectStore'); let data = { id: 1, name: 'John', age: 25 }; let request = objectStore.add(data); request.onsuccess = (event) => { console.log('Data added successfully'); }; request.onerror = (event) => { console.error('Error adding data'); }; }; ``` 还可以使用索引检索数据: ```javascript request.onsuccess = (event) => { let db = event.target.result; let transaction = db.transaction('myObjectStore', 'readonly'); let objectStore = transaction.objectStore('myObjectStore'); let index = objectStore.index('name'); let request = index.get('John'); request.onsuccess = (event) => { let data = event.target.result; console.log(`Name: ${data.name}, Age: ${data.age}`); }; request.onerror = (event) => { console.error('Error retrieving data'); }; }; ``` 此外,还可以更新和删除数据、创建和删除索引等等。这只是一个简单的使用 IndexedDB 的示例,实际应用中可以根据需求进行更复杂的操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值