H5存储

1.本地存储-Web Storage
2.本地存储-IndexedDB
3.本地存储的扩展介绍
4.离线存储-app cache
5.总结

分析存储需求:

  1. 移动端网络环境因素
  • 数据响应慢,体验下降,2G/3G网速非常慢
  1. 流量因素
  • 客户端存储 = 节省流量 = 节省金钱
  1. 追求原生体验
  • 离线使用应用
  • 存储应用相关资源、数据

Cookie 可行否? 否

因为Cookie 的局限性:

  • 存储大小限制,仅 4kb 左右
  • 单个域名下的数量限制,50个左右
  • 污染请求头,浪费流量

说明:

  • cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,
    而Web Storage仅仅是为了在本地“存储”数据而生。
  • 每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽。

本地存储:localStorage 和 sessionStorage

  1. 相同的使用方法
  • 使用 setItem(key,value) 方法设置存储内容
  • 使用 getItem(key) 方法获取存储内容
  • 使用 removeItem(key) 方法删除存储内容
  • 使用 clear() 方法清除所有内容
  • 使用 length 属性获取存储内容个数
  • 使用 key(index) 方法获取存储字段
  1. 不同的存储时效
  • localStorage 存储会持久化
  • sessionStorage 存储会在网页会话结束(标签页的关闭)后失效,只有在同一个会话中的页面才能访问。
  1. 不同的存储容量
  • localStorage 容量一般在 2 – 5Mb 左右
  • sessionStorage 存储容量不一,部分浏览器不设限
  1. Web Storage Support Test
    http://dev-test.nemikor.com/web-storage/support-test/

sessionStorage和localStorage的存储空间虽然较大,但是存储容量仍有限制,叫做配额。

  1. 使用 Storage 时的注意点:
  1. 存储容量超出限制
  • 抛出 QuotaExceededError 异常 (存储值时应使用 try catch 捕获异常)




    
    quota exceed test



    
    



  1. 存储类型的限制
  • 仅能存储字符串
  • 注意类型转换 JSON.stringifyJSON.parse



  
  quota exceed test


    










打印结果:

> abc | string
> false | string
> undefined | string
> null | string
> 0 | string
>  | string
> 1,2,3 | string
> [object Object] | string
> [object Object] | string
> toStringed | string
> 100 | string

类型转换:在控制台输入

> localStorage.setItem('key',JSON.stringify({data:1}))
< undefined
> localStorage.getItem('key')
< "{"data":1}"
> JSON.parse(localStorage.getItem('key'))
< {data: 1}
  1. sessionStorage 失效机制
  • 刷新页面并不会失效 location.reload()
  • 相同 URL 不同标签页不能共享 sessionStorage
  1. Web Storage 的优化
    性能与存储容量大小无关,与读取次数有关
  • 减少读取 item 次数
  • 单个 item 中尽可能多的存储数据
  1. 带有过期机制的 localStorage 的功能需求
  1. 可以设置数据的存储时间
  2. 过期数据清理
  3. 自行维护存储空间



  
  cache storage

  



IndexedDB 数据库

1.了解indexedDB数据库

1)indexedDB数据库是一种事务型数据库
2)是NoSQL数据库
3)使用JS对象存储数据

2.如何创建数据库和表

  1. 如何创建数据库和"表"?
  1. indexedDB.open('dbName',dbVersinNumber) 创建数据库,返回 IDBOpenDBRequest 对象
  2. indexedDB.createObjectStore 创建“表”
  3. indexedDB.deleteDatabase('dbName') 删除数据库
    function createDB() {
        // request 是 IDBOpenDBRequest对象。 
        request = db.open(dbName, version)
        //请求有三种状态,如下:
        request.onsuccess = function() { // 打开数据库成功
            db = request.result;
            console.log('open success');

        }

        request.onerror = function(e) { // 打开数据库失败
            console.log(e.currentTarget.errormessage)
        }

        request.onupgradeneeded = function(e) { //请求数据库版本变化时
            var store = null;
            db = e.target.result;
            console.log('upgradeneeded');

            /*
            if (!db.objectStoreNames.contains(osName)) {
                db.createObjectStore(osName, {autoIncrement: true}) // 创建的表的主建是自增型的
            }
            */

            if (!db.objectStoreNames.contains(osName)) {
                store = db.createObjectStore(osName, { keyPath: 'id' }) // 创建的表以字段为主建
                store.createIndex('idIndex', 'id', { unique: true }); //创建索引字段id唯一
                store.createIndex('categoryIndex', 'category', { multiEntry: true }); //创建索引字段为数组
                store.createIndex('hpIndex', 'hp', { unique: false });
            }                
           
        }

        // onsuccess事件在onupgradeneeded事件之后触发
    }
  1. 设置主键的两种方法
  1. 设置自增主键 - {autoIncrement: true}
db.createObjectStore(osName, {autoIncrement: true})
  1. 取数据中字段作为主键 - {keyPath: 字段名}
store = db.createObjectStore(osName, { keyPath: 'id' })

3. 关于表的增删改查

  1. 如何使用事务获取表
    调用 IDBDatabase.transaction 方法会返回一个 IDBTransaction 对象,
    它含有一个 objectStore 方法, 可以让用户通过指定模式操作数据库中的“表”。

indexedDB -> transaction -> objectStore

//osName 表格名称,
var db = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
var transaction = db.transaction(osName, 'readwrite'), //打开一个事务,读写模式
store = transaction.objectStore(osName);
  1. 事务的模式
  1. 读写模式 - readwrite
  2. 只读模式(默认) - readonly
  3. 版本变更模式 - versionchange
  1. 关于“表”的增删查改的相关方法
  1. 增加数据 – IDBObjectStore.add
  2. 获取数据 – IDBObjectStore.get
  3. 获取所有数据 – IDBObjectStore.getAll
  4. 修改(或新增)数据 – IDBObjectStore.put
  5. 删除数据 – IDBObjectStore.delete
  6. 清除所有数据 – IDBObjectStore.clear
    这些方法都返回一个 IDBRequest 对象。
    function addData() {
        if (!db) { alert("db"); }

        // 调用 `IDBDatabase.transaction` 方法会返回一个 IDBTransaction 对象,
        // 它含有一个 objectStore 方法, 可以让用户通过指定模式操作数据库中的“表”。
        var transaction, store;
        transaction = db.transaction(osName, 'readwrite'); //打开一个事务,读写模式
        store = transaction.objectStore(osName) ///获取osName指定的 object store

        data.map(function(o) {
            store.add(o)
            // request = store.add(o) //增加数据
            //   if (data.length - 1 === i) {
            //     request.onsuccess = function () {
            //       console.log('alreay add all data to db')
            //       showCurrentData()
            //     }
            //   }
        })
    }

    function getData(id) {
        var transaction = db.transaction(osName, 'readwrite'), //打开一个事务,读写模式
            store = transaction.objectStore(osName);
        var request = store.get(id);
        request.onsuccess = function() {
            console.log(request.result);
        }

    }


    function getAllData() {
        var transaction = db.transaction(osName, 'readwrite'), //打开一个事务,读写模式
            store = transaction.objectStore(osName);
        var request = store.getAll();
        request.onsuccess = function() {
            console.log(request.result);
        }

    }


    function updateData(id) {
        var transaction = db.transaction(osName, 'readwrite'), //打开一个事务,读写模式
            store = transaction.objectStore(osName);
        var request = store.get(id);
        request.onsuccess = function() {
            request = store.put({ //更新即可以更新也可以添加,取决于关键字是否有重复
                name: '小花猫',
                id: id,
                hp: 9
            });
        }

    }


    function deleteData(id) {
        var transaction = db.transaction(osName, 'readwrite'), //打开一个事务,读写模式
            store = transaction.objectStore(osName);
        var request = store.delete(id);

        request.onsuccess = function() {
            console.log('delete success');
        }

    }

    function clear() {
        var transaction = db.transaction(osName, 'readwrite'), //打开一个事务,读写模式
            store = transaction.objectStore(osName);
        var request = store.clear();
        request.onsuccess = function() {
            console.log('clear success');
        }

    }
  1. IDBRequest 对象
  1. 使用 IDBRequest.onsuccess 执行查询完成回调
  2. 使用 IDBRequest.result 获取查询结果
  3. 使用 IDBRequest.onerror 执行查询失败回调

4. 关于索引

  1. 如何创建索引 IDBObjectStore.createIndex
  • indexName: 索引名称
  • keyPath: 索引字段,可以为空或者数组(type array)
  • optionParameters: 索引配置参数
store = db.createObjectStore(osName, { keyPath: 'id' }) // 创建的表以字段为主建
store.createIndex('idIndex', 'id', { unique: true }); //创建索引字段id唯一
store.createIndex('categoryIndex', 'category', { multiEntry: true }); //创建索引字段为数组
store.createIndex('hpIndex', 'hp', { unique: false });
  1. optionParameters: 索引配置参数
  1. unique 表示keyPath字段的数据是否唯一
    2)multiEntry 表示是否为 keyPath 字段的每一项建立一条索引数据
  1. 使用索引的好处
  1. 可以使用存储记录中的值进行检索
  2. 索引自动更新
  3. 索引数据自动排序
  1. 索引的相关方法
    1)查询数据 - IDBIndex.get
  1. 查询所有数据 - IDBIndex.getAll
  2. 打开游标 - IDBIndex.openCursor
function useIndexGetData() { // 索引只能查询数据,并不能操作数据
    var transaction = db.transaction(osName, 'readwrite'), //打开一个事务,读写模式
        store = transaction.objectStore(osName),
        index = store.index('categoryIndex');
        request = index.getAll('飞行');

    request.onsuccess = function() {
        console.log(request.result);
    }
}

5. 关于游标

  1. 如何创建游标?
    IDBObjectStore/IDBIndex.openCursor
  • 接收可选参数 range 和 direction,指明游标遍历的范围和方向
  • 返回一个 IDBRequet 对象,异步方法
  • 该 IDBRequet 对象的结果是一个 IDBCursor 对象
  1. IDBKeyRange 对象
    1)upperBound: 指定游标范围的上限
    2)lowerBound: 指定游标范围的下限
    3)bound: 指定游标范围的区间
    4)only: 指定游标的值

key range 取值表:



  1. direction 参数
  • next: 顺序查询
  • nextunique: 顺序唯一查询
  • prev: 逆序查询
  • prevunique: 逆序唯一查询
function useCursorGetData() {
    var transaction = db.transaction(osName, 'readwrite'), //打开一个事务,读写模式
        store = transaction.objectStore(osName),
        // request=store.openCursor();  //创建游标
        // request=store.openCursor(IDBKeyRange.only('002'));  //指定游标KeyRange,only一个
        // request = store.openCursor(null, 'prev');
        request = store.openCursor(IDBKeyRange.lowerBound('002'), 'prev'); //逆序查询,游标范围下限是"002"
    request.onsuccess = function() {
        var cursor = request.result;
        if (cursor) {
            console.log(cursor.value);
            cursor.continue();
        }
    }
}

6. 索引和游标的结合使用

  1. 索引和游标的优势
    索引:可以按值搜索
    游标:可以选择遍历顺序及操作数据
function useIndexAndCursorOperateData1() { // 索引和游标结合,可以查询和操作数据
    var transaction = db.transaction(osName, 'readwrite'), //打开一个事务,读写模式
        store = transaction.objectStore(osName),
        index=store.index('categoryIndex');
        request=index.openCursor();

    request.onsuccess = function() {
        var cursor = request.result;
        if (cursor) {
            if(cursor.value.id==='002'){

               /* // 更新数据
               cursor.update({  
                      name: '小蝙蝠',
                      id: '002',
                      hp: 10,
                      category:['怪物','飞行']
                })
                */ 

                 // 删除数据
                cursor.delete().onsuccess=function () {  
                    console.log('delete success');         
                }
                        
            }
            // 更新数据和删除数据操作都是异步操作,所以输出可能会混乱
            console.log(cursor.value);
            cursor.continue();
        }
    }
}

function useIndexAndCursorOperateData() { // 索引和游标结合,可以查询和操作数据
    var transaction = db.transaction(osName, 'readwrite'), //打开一个事务,读写模式
        store = transaction.objectStore(osName),
        index = store.index('hpIndex');
        // request = index.openCursor(IDBKeyRange.upperBound(5)); // 5(包含5)以下
        request = index.openCursor(IDBKeyRange.bound(5,10,true,true)); // 范围(5到10)

    request.onsuccess = function() {
        var cursor = request.result,value=null;
        if (cursor) {
            
            value = cursor.value;
            value.hp += 20;
            cursor.update(value);
            
            console.log(cursor.value);
            cursor.continue();
        }
    }
}

IndexedDB 与 Web Storage 比较

  1. indexedDB 的优势:
  • 存储类型更加丰富
  • 可实现高级查询
  • 可在 Web Workers 中使用
  • 存储容量更大
  1. Web Storage 的优势
  • API 较少,更容易掌握
  • 兼容性更好
  1. IndexedDB 的兼容性问题
    1)IOS8 & 9 中 webview 不支持 indexedDB
    2)Firefox 单次存储 Blob 数据超 50Mb 会抛出异常, 这个50M可以在IndexDB的一些API中进行修改
    3)Safari 的 indexedDB 不能用于 web workers
    4)Chrome36 不支持存储类型的数据

其他存储方式介绍

1. WebSQL

  • 关系型数据库
  • 随HTML5规范加入, 在浏览器端运行的轻量级数据库。
  1. WebSQL 的 API 有哪些?
  • openDatabase: 打开数据库
  • transaction: 获取事务,进行数据库操作
  • executeSql: 执行 SQL 进行查询
  1. WebSQL 的现状
  • 兼容性问题严重


  • W3C 已经不再积极处理其相关规范(避免使用WebSQL)

2. Filesystem & FileWriter API

  • 供我们在客户端进行文件的存储
  • 但是和WebSQL有相似的命运,有严重的兼容性问题和规范被废弃(避免使用)。


3. UserData

是IE独有的存储方式:

  • 只在Windows系统的IE中存在
  • 容量不大

4. Cookie

  • 存储大小限制,仅 4kb 左右
  • 单个域名下的数量限制,50个左右
  • 污染请求头,浪费流量

你可能感兴趣的:(H5存储)