H5存储

2018-06-20  本文已影响54人  lrxxhyf

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

分析存储需求:

  1. 移动端网络环境因素
  1. 流量因素
  1. 追求原生体验

Cookie 可行否? 否

因为Cookie 的局限性:

说明:

本地存储:localStorage 和 sessionStorage

  1. 相同的使用方法
  1. 不同的存储时效
  1. 不同的存储容量
  1. Web Storage Support Test
    http://dev-test.nemikor.com/web-storage/support-test/

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

  1. 使用 Storage 时的注意点:
  1. 存储容量超出限制
<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>quota exceed test</title>
</head>

<body>
    <button class="start-btn">start</button>
    <script>
    var btn = document.querySelector('.start-btn');


    var data = '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890',
        id = 0,
        len = data.length,
        total = 0,
        key;

    function save() {
        id = (id + 1) % 10;
        key = Date.now() + '' + id;
        // try...catch 主要用于捕获代码运行时的异常,并进行异常处理。
        // try 部分包含运行时,可能出现异常的代码.
        // 而 catch 部分包含错误发生时运行的代码。
        try {
            // try 中写可能产生异常的语句
            localStorage.setItem(key, data);
            save();
        } catch (e) {
            // catch 中写负责异常处理的语句
            console.log(e.name); //QuotaExceededError

        }

    }
    btn.addEventListener('click', save);

    </script>
</body>

</html>
  1. 存储类型的限制
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>quota exceed test</title>
</head>
<body>
    <button class="str" onclick="save('abc')">字符串 abc</button><br />   
    <button class="bool" onclick="save(false)">布尔值 false</button><br />
    <button class="undef" onclick="save(window.undefined)">未定义 window.undefined</button><br />
    <button class="null" onclick="save(null)">空值 null</button><br />
    <button class="num" onclick="save(0)">数字 0</button><br />
    <button class="arr1" onclick="save([])">数组 []</button><br />
    <button class="arr2" onclick="save([1,2,3])">数组 [1,2,3]</button><br />
    <button class="obj1" onclick="save({})">对象 {}</button><br />
    <button class="obj2" onclick="save({x: 1})">对象 {x: 1}</button><br />
    <button class="obj3" onclick="save({toString: function () {return 'toStringed'}})">对象 {toString: function () {return 'toStringed'}}</button><br />
    <button class="obj4" onclick="save({toString: function () {return 100}})">对象 {toString: function () {return 100}}</button><br />
    
    
<script>
function save (data) {
    localStorage.setItem('key', data)
    show(localStorage.getItem('key'))
}

function show (value) {
    console.log(value, '|', typeof value)
}

</script>
</body>
</html>  

打印结果:

> 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 失效机制
  1. Web Storage 的优化
    性能与存储容量大小无关,与读取次数有关
  1. 带有过期机制的 localStorage 的功能需求
  1. 可以设置数据的存储时间
  2. 过期数据清理
  3. 自行维护存储空间
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>cache storage</title>
</head>
<body>  
<script>
'use strict'
;(function () {
    var ls = window.localStorage

    function oops () {
        return console.warn('your browser is not supported localStorage API')
    }

    function getItem (key) {
        var data = ls.getItem(key)  //在没有数据项的情况下,data为null
        data = JSON.parse(data)||{} //将字符串类型的data转为对象类型的data

        if (data.time === 0) {// 上句如是data = JSON.parse(data),在data.time时,就会报错。所以调整成data = JSON.parse(data)||{}
            // 持久化数据直接返回
            return data.value
        } else if (Date.now() > data.time) { // 判断是否超时
            //过期
            ls.removeItem(key) 
            return ''
        } else {
            // 没过期
            return typeof data.value !== 'undefined' ? data.value : ''
        }
    }

    function setItem (key, value, time) {
        if (typeof key === 'undefined') {return}
        var data = {
            time: time ? Date.now() + time : 0,
            value: value
        }
        data = JSON.stringify(data) //stringify方法进行对象的字符串序列化
        try {
            ls.setItem(key, data)
        } catch (e) {
            ls.clear()
            ls.setItem(key, data)
        }
        
    }

    function removeItem (key) {
        ls.removeItem(key)
    }

    function clear () {
        ls.clear()
    }

    window.cacheStorage = {//浏览器支持使用localStorage,不支持输出提示语
        getItem: ls ? getItem : oops,
        setItem: ls ? setItem : oops,
        removeItem: ls ? removeItem : oops,
        clear: ls ? clear : clear
    }
})()
</script>
</body>
</html>

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
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
  1. IDBKeyRange 对象
    1)upperBound: 指定游标范围的上限
    2)lowerBound: 指定游标范围的下限
    3)bound: 指定游标范围的区间
    4)only: 指定游标的值

key range 取值表:



  1. direction 参数
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 的优势:
  1. Web Storage 的优势
  1. IndexedDB 的兼容性问题
    1)IOS8 & 9 中 webview 不支持 indexedDB
    2)Firefox 单次存储 Blob 数据超 50Mb 会抛出异常, 这个50M可以在IndexDB的一些API中进行修改
    3)Safari 的 indexedDB 不能用于 web workers
    4)Chrome36 不支持存储类型的数据

其他存储方式介绍

1. WebSQL

  1. WebSQL 的 API 有哪些?
  1. WebSQL 的现状

2. Filesystem & FileWriter API

3. UserData

是IE独有的存储方式:

4. Cookie

上一篇下一篇

猜你喜欢

热点阅读