title: Storage
categories: Javascript
tag:

  • storage
    date: 2021-11-30 11:35:34

认识 Storage

WebStorage 主要提供了一种机制,可以让浏览器提供一种比 cookie 更直观的 key、value 存储方式:

  • localStorage:本地存储,提供的是一种永久性的存储方法,在关闭掉网页重新打开时,存储的内容依然保留;
  • sessionStorage:会话存储,提供的是本次会话的存储,在关闭掉会话时,存储的内容会被清除;

localStorage 和 sessionStorage 区别

我们会发现 localStorage 和 sessionStorage 看起来非常的相似。

那么它们有什么区别呢?

  • 验证一:关闭网页后重新打开,localStorage 会保留,而 sessionStorage 会被删除;
  • 验证二:在页面内实现跳转,localStorage 会保留,sessionStorage 也会保留;
  • 验证三:在页面外实现跳转(打开新的网页),localStorage 会保留,sessionStorage 不会被保留;

Storage 常见的方法和属性

Storage 有如下的属性和方法:

属性:

  • Storage.length:只读属性
    1. 返回一个整数,表示存储在 Storage 对象中的数据项数量;

方法:

  • Storage.key():该方法接受一个数值 n 作为参数,返回存储中的第 n 个 key 名称;
  • Storage.getItem():该方法接受一个 key 作为参数,并且返回 key 对应的 value;
  • Storage.setItem():该方法接受一个 key 和 value,并且将会把 key 和 value 添加到存储中。
    1. 如果 key 存储,则更新其对应的值;
  • Storage.removeItem():该方法接受一个 key 作为参数,并把该 key 从存储中删除;
  • Storage.clear():该方法的作用是清空存储中的所有 key;

封装 Storage

27_Storage - 图1

  1. class HyCache {
  2. constructor(isLocal = true) {
  3. this.storage = isLocal ? localStorage : sessionStorage
  4. }
  5. setItem(key, value) {
  6. if (value) {
  7. this.storage.setItem(key, JSON.stringify(value))
  8. }
  9. }
  10. getItem(key) {
  11. let value = this.storage.getItem(key)
  12. if (value) {
  13. value = JSON.parse(value)
  14. return value
  15. }
  16. }
  17. removeItem(key) {
  18. this.storage.removeItem(key)
  19. }
  20. clear() {
  21. this.storage.clear()
  22. }
  23. key(index) {
  24. return this.storage.key(index)
  25. }
  26. length() {
  27. return this.storage.length
  28. }
  29. }
  30. const localCache = new HyCache()
  31. const sessionCache = new HyCache()
  32. export { localCache, sessionCache }

认识 IndexedDB

什么是 IndexedDB 呢?

  • 我们能看到 DB 这个词,就说明它其实是一种数据库(Database),通常情况下在服务器端比较常见;
  • 在实际的开发中,大量的数据都是存储在数据库的,客户端主要是请求这些数据并且展示;
  • 有时候我们可能会存储一些简单的数据到本地(浏览器中),比如 token、用户名、密码、用户信息等,比较少存储大量的数据;
  • 那么如果确实有大量的数据需要存储,这个时候可以选择使用 IndexedDB;

IndexedDB 是一种底层的 API,用于在客户端存储大量的结构化数据。

  • 它是一种事务型数据库系统,是一种基于 JavaScript 面向对象数据库,有点类似于 NoSQL(非关系型数据库);
  • IndexDB 本身就是基于事务的,我们只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列事务即可;

IndexedDB 的连接数据库

第一步:打开 indexDB 的某一个数据库;

  1. 通过 indexDB.open(数据库名称, 数据库版本)方法;
  2. 如果数据库不存在,那么会创建这个数据;
  3. 如果数据库已经存在,那么会打开这个数据库;

第二步:通过监听回调得到数据库连接结果;

  1. 数据库的 open 方法会得到一个IDBOpenDBRequest类型
  2. 我们可以通过下面的三个回调来确定结果:
    • onerror:当数据库连接失败时;
    • onsuccess:当数据库连接成功时回调;
    • onupgradeneeded:当数据库的 version 发生变化并且高于之前版本时回调;
      • 通常我们在这里会创建具体的存储对象:db.createObjectStore(存储对象名称, { keypath: 存储的主键 })
  3. 我们可以通过 onsuccess 回调的 event 获取到 db 对象:event.target.result
  1. //why相当于数据库的库
  2. const dbRequest = indexedDB.open('why')
  3. dbRequest.onerror = function (err) {
  4. console.log('打开数据库失败')
  5. }
  6. let db = null
  7. dbRequest.onsuccess = function (event) {
  8. db = event.target.result
  9. }
  10. // 第一次打开或者版本更新
  11. dbRequest.onupgradeneeded = function (event) {
  12. const db = event.target.result
  13. //创建一些存储对象.
  14. // users相当于数据库中的表
  15. // keyPath相当于数据库中的primary key
  16. db.createObjectStore('users', { keyPath: 'id' })
  17. }

27_Storage - 图2

IndexedDB 的数据库操作

新增

我们先以构造函数的方式批量新建对象

  1. class User {
  2. constructor(id, name, age) {
  3. this.id = id
  4. this.name = name
  5. this.age = age
  6. }
  7. }
  8. const users = [
  9. new User(100, 'why', 18),
  10. new User(101, 'dh', 22),
  11. new User(102, 'gwk', 22),
  12. new User(103, 'kk', 30)
  13. ]

然后点击新增按钮。插入数据

27_Storage - 图3

查询

  1. case 1:
  2. console.log('点击了查询')
  3. //查询方式1:(根据主键查询)
  4. const request = store.get(102)
  5. request.onsuccess = function (event) {
  6. console.log(event.target.result)
  7. }
  8. break

27_Storage - 图4

批量查询

  1. case 1:
  2. console.log('点击了查询')
  3. const request = store.openCursor()
  4. request.onsuccess = function (event) {
  5. const cursor = event.target.result
  6. if (cursor) {
  7. console.log(cursor.key, cursor.value)
  8. cursor.continue()
  9. } else {
  10. console.log('查询完成')
  11. }
  12. }
  13. break

27_Storage - 图5

修改

  1. case 2:
  2. console.log('点击了修改')
  3. const updateRequest = store.openCursor()
  4. updateRequest.onsuccess = function (event) {
  5. const cursor = event.target.result
  6. if (cursor) {
  7. if (cursor.key === 101) {
  8. const value = cursor.value
  9. value.name = 'curry'
  10. cursor.update(value)
  11. console.log('修改成功')
  12. } else {
  13. cursor.continue()
  14. }
  15. }
  16. }
  17. break

27_Storage - 图6

删除

  1. case 3:
  2. console.log('点击了删除')
  3. const deleteRequest = store.openCursor()
  4. deleteRequest.onsuccess = function (event) {
  5. const cursor = event.target.result
  6. if (cursor) {
  7. if (cursor.key === 101) {
  8. cursor.delete()
  9. console.log('删除成功')
  10. } else {
  11. cursor.continue()
  12. }
  13. }
  14. }

27_Storage - 图7

完整代码

  1. const dbRequest = indexedDB.open('why')
  2. dbRequest.onerror = function (err) {
  3. console.log('打开数据库失败')
  4. }
  5. let db = null
  6. dbRequest.onsuccess = function (event) {
  7. db = event.target.result
  8. }
  9. // 第一次打开或者版本更新
  10. dbRequest.onupgradeneeded = function (event) {
  11. const db = event.target.result
  12. //创建一些存储对象.
  13. // users相当于数据库中的表
  14. // keyPath相当于数据库中的primary key
  15. db.createObjectStore('users', { keyPath: 'id' })
  16. }
  17. class User {
  18. constructor(id, name, age) {
  19. this.id = id
  20. this.name = name
  21. this.age = age
  22. }
  23. }
  24. const users = [
  25. new User(100, 'why', 18),
  26. new User(101, 'dh', 22),
  27. new User(102, 'gwk', 22),
  28. new User(103, 'kk', 30)
  29. ]
  30. const btns = document.querySelectorAll('button')
  31. for (let i = 0; i < btns.length; i++) {
  32. btns[i].onclick = function () {
  33. const transaction = db.transaction('users', 'readwrite')
  34. const store = transaction.objectStore('users')
  35. switch (i) {
  36. case 0:
  37. console.log('点击了新增')
  38. for (const user of users) {
  39. const request = store.add(user)
  40. request.onsuccess = function () {
  41. console.log(`插入${user.name}成功`)
  42. }
  43. }
  44. transaction.oncomplete = function () {
  45. console.log('添加操作全部完成')
  46. }
  47. break
  48. case 1:
  49. console.log('点击了查询')
  50. //查询(根据主键查询)
  51. // const request = store.get(102)
  52. // request.onsuccess = function (event) {
  53. // console.log(event.target.result)
  54. // }
  55. const request = store.openCursor()
  56. request.onsuccess = function (event) {
  57. const cursor = event.target.result
  58. if (cursor) {
  59. console.log(cursor.key, cursor.value)
  60. cursor.continue()
  61. } else {
  62. console.log('查询完成')
  63. }
  64. }
  65. break
  66. case 2:
  67. console.log('点击了修改')
  68. const updateRequest = store.openCursor()
  69. updateRequest.onsuccess = function (event) {
  70. const cursor = event.target.result
  71. if (cursor) {
  72. if (cursor.key === 101) {
  73. const value = cursor.value
  74. value.name = 'curry'
  75. cursor.update(value)
  76. console.log('修改成功')
  77. } else {
  78. cursor.continue()
  79. }
  80. }
  81. }
  82. break
  83. case 3:
  84. console.log('点击了删除')
  85. const deleteRequest = store.openCursor()
  86. deleteRequest.onsuccess = function (event) {
  87. const cursor = event.target.result
  88. if (cursor) {
  89. if (cursor.key === 101) {
  90. cursor.delete()
  91. console.log('删除成功')
  92. } else {
  93. cursor.continue()
  94. }
  95. }
  96. }
  97. }
  98. }
  99. }