zoukankan      html  css  js  c++  java
  • 《客户端存储技术》阅读笔记

    本文地址: https://www.cnblogs.com/veinyin/p/12928687.html

    1.0 前言

    本文是《客户端存储技术》阅读笔记,标题与该书基本保持一致

    1.1客户端存储优缺点

    优点:

    • 直接访问数据,比从服务端获取更快

    • 节省网络流量,一次请求可以使用多次

    • 减轻服务器压力,避免重复多次请求

    • 创建离线应用程序成为可能

    缺点:

    • 数据同步问题

    • 存储限制模糊,无法确定可使用资源量

    • 没有专业数据库功能强大

    1.2 Cookie

    Cookie 会被带在请求头和响应头在客户端和服务端来回传递,因此存放几十个键值对即可,不建议大数据量

    不需要服务端知晓的数据不建议存放在 Cookie 中,可以存用户偏好和基础信息等

    Cookie 自身使用方法:

    • 存。键值对、其他设置如过期时间、可用域名等,分号分隔

      document.cookie = "name=yyh; expires=Fri, 31 Dec 9999 23:59:59 GMT; domain=app.foo.com"
    • 取 。获取的是所有 Cookie 内容,需自行解析

      document.cookie
    • 删。将过期时间修改为过去即可

      document.cookie = "name=yyh; expires=Thu, 01 Jan 1970 00:00:00 GMT"

     

    使用时上述方式存取 Cookie 很不方便,因此项目中可以使用 js-cookie 库

    1.3 Web存储

    Web 存储指的是 Local Storage(本地存储) 和 Session Storage(会话存储),可存储较大数据量,5-10M

    不支持复杂数据,只支持字符串(数组或对象可编码为 Json 后存储),适用于存储用户偏好等简单信息

    数据变化时会触发 window 上的 storage 事件,可获取 key、newValue、oldValue 等(必须是两个同源 tab,一个 tab 中修改数据,另一个 tab 中触发!同一个 tab 中监听不到变化)

    本地存储只要用户不删除就会一直存在

    会话存储只要浏览器关闭就会清除

    使用方法(Local Storage 和 Session Storage 相同):

    • localStorage.setItem('name', 'yyh')
      sessionStorage.setItem('name', 'yyh')
    • localStorage.getItem('name')
    • localStorage.removeItem('name')

     

    • 清除所有键值对

      localStorage.clear()

    1.4 indexedDB

    indexedDB 是一个存储系统,可以存储想要存储的任意数据,移动端支持不够友好

    代码示例

    1.4.1 关键术语

    • 数据库: 存储数据的地方,一般情况下,一个网站创建一个数据库即可

    • 对象存储:无严格数据格式要求,add 时必须是个对象,至于对象的值可以是任意类型

    • 索引:通过该索引过滤所需数据

    1.4.2 操作数据前准备

     

    1. 使用前需先检测浏览器是否支持
    if('indexedDB' in window)
    1. 如果支持,就可以打开数据库了

    var openResult = indexedDB.open(dbName, dbVersionNumber)
    ​
    // 首次访问数据库或版本号变化时触发
    openResult.onupgradeneeded = (e) => {
      // 创建对象存储
    }
    ​
    // 成功
    openResult.onsuccess = (e) => { db = e.target.result }
    ​
    // 失败
    openResult.onerror = (e) => {}
    1. 创建对象存储

    openResult.onupgradeneeded = (e) => {
      // 数据库对象
      db = e.target.result
      if(!db.objectStoreNames.contains('Person')) {
        // 创建对象存储,第二个参数是配置属性可不传,此处将自增值赋给 id 作为主键
        let PersonOS = db.createObjectStore('Person', { keyPath: 'id', autoIncrement: true }) 
        // 创建索引 [索引名,数据属性,options(指定如何操作属性)],也可以不创建索引
        PersonOS.createIndex('age', 'age', { unique: false })
      }
    }

    如果需要更新对象存储,则需先更改版本号,再在这个事件触发时更新

    1.4.3 操作数据

    1.4.3.1 创建(新增)数据(add)

    创建数据需在 onsuccess 事件中,获取的 db 对象可以作为全局变量,便于后续添加数据使用

    openResult.onsuccess = (e) => {
      // 监听事件并创建数据(此处仅展示添加数据的代码)
      const db = e.target.result
      // 获取事务
      const transaction = db.
      ('Person', 'readwrite')
      // 获取事务
      
      对象存储
      const store = transaction.objectStore('Person')
      const person = {
        name: 'yyh',
        age: 18
      }
      const request = store.add(person)
      request.onsuccess = e => {}
      request.onerror = e => {}
    }

    1.4.3.2 读取数据(get)

    读取一条数据,本方法中 db 为上述存储的全局变量,get 方法参数是之前设置的主键的值,本例中是 id 的值

    getPersonById() {
      const transaction = db.transaction('Person', 'readonly')
      const store = transaction.objectStore('Person')
      const request = store.get(1) // 主键的值
      request.onsuccess = e => {
        const result = e.target.result  // result 就是查询的结果
      }
      request.onerror = e => {}
    }

    1.4.3.3 更新数据(put)

    更新数据与创建数据基本是一样的,更新某一项时,必须要把整个对象传入 put 方法,不能只传一个字段

    如果没有对应的主键就会新增一条

    update() {
      const transaction = db.transaction('Person', 'readwrite')
      const store = transaction.objectStore('Person')
      const person = {
        ...getPersonResult, // 读取数据的结果,包含了主键 id 的值
        age: 16, // 这是要更新的字段
      }
      const request = store.put(person)
      request.onsuccess = e => {}
      request.onerror = e => {}
    }

    1.4.3.4 删除数据(delete)

    传入要删除的主键值即可,本例中要删除的是 id = 2 那条

    const transaction = db.transaction('Person', 'readwrite')
    const store = transction.objectStore('Person')
    const request = store.delete(2)
    request.onsuccess = e => {}
    request.onerror = e => {}

    1.4.4 获取所有数据

    在对象存储上打开游标(cursor)来获取所有数据

    getAll() {
      const transaction = db.transaction('Person', 'readonly')
      const store = transaction.objectStore('Person')
      // 打开游标,注意是在对象存储上打开的
      const cursor = store.openCursor()
      // 结果列表
      let resultList = []
      cursor.onsuccess = e => {
        const cursor = e.target.result
        // cursor.value 中就是一条查询结果
        resultList.push(cursor.value)
        // 如果数据没读取结束,继续读下一条
        cursor.continue()
      }
      transaction.oncomplete = () {
        // 数据获取结束,可以对结果操作了
      }
    }

    1.4.5 获取部分数据

    在索引上打开游标来获取部分数据

    范围由 IDBKeyRange API 创建,提供四个函数:lowerBound、upperBound、bound、only,includes 也提供了但 IE 不支持。默认是闭区间,默认遍历顺序是 forward

    • lowerBound。参数:[lower, boolean = false] ,boolean = true 则为开区间

    • upperBound。参数:[upper, boolean = false]

    • bound。参数:[lower, upper, lowerbool, upperbool]

    filter() {
        // 假设lower、upper都通过页面输入获取了
      // 如果没有输入范围,不过滤
      if(!lower && !upper) return 
      
      // 确定范围
      let range
      // 如果上下限都输入了
      if(lower && upper) {
        range = IDBKeyRange.bound(lower, upper)
      } else if(lower) {
        // 只输入了下限
        range = IDBKeyRange.lowerBound(lower)
      } else {
        // 只输入了上限
        range = IDBKeyBound.upperBound(upper)
      }
      
      const transaction = db.transaction('Person', 'readonly')
      const store = transaction.objectStore('Person')
      const index = store.index('age') // age 是之前创建好的索引
      
      // 结果列表
      let resultList = []
      
      // 打开游标 第二个参数确定遍历顺序,默认顺序,逆序传'prev'
      const cursor = index.openCursor(range)
      cursor.onceccess = e => {
        const cursor = e.target.result
        if(cursor) {
          resultList.push(cursor.value)
          cursor.continue()
        }
      }
      
      // 查询结束
      transaction.oncomplete = e => {
        console.log(resultList)
      }
    }

    1.4.6 补充

    如果要在一个值为数组的字段上建立索引,options中加上 multiEntry: true 即可,如

    db.createIndex('hobbies', 'hobbies', { unique: false, multiEntry: true })

    如果要获取对象存储中的数据量,直接通过count()即可

    const count = db.transaction('Person', 'readonly').objectStore('Person').count()
    count.onsuccess = e => {
      let count = e.target.result // 这就是数据量
    }

        

     

     

    END~~~≥ω≤ 

     

     

     

     

     

     

     

  • 相关阅读:
    x01.Weiqi.6: 立体棋子
    x01.Game.MapEditor: 地图编辑器
    SQL Server插入中文出现乱码??的解决办法
    Cachecontrol使用:header('Cachecontrol:private')
    验证身份证号码Javascript代码
    .Net GDI+缩放绘图
    Access(JETSQL)问题集锦
    Android开发中Google谷歌地图坐标系怎么转Baidu百度地图坐标系
    21、桥接模式(Bridge模式)详解
    22、装饰模式(装饰设计模式)详解
  • 原文地址:https://www.cnblogs.com/veinyin/p/12928687.html
Copyright © 2011-2022 走看看