H5的离线存储方案

作者: grain先森 | 来源:发表于2019-01-31 10:25 被阅读455次

    1. Web SQL Database

    HTML5的存储还有一种Web SQL Database方式,虽然还有浏览器支持,是唯一的关系数据库结构的存储,但W3C以及停止对其的维护和发展,所以这里我们也不再对其进行介绍:Beware. This specification is no longer in active maintenance and the Web Applications Working Group does not intend to maintain it further.


    Web SQL Database

    整个示例主要就是将HT for Web的DataModel数据模型信息进行序列化和反序列化,这个过程很简单通过dataModel.serialize()将模型序列化成JSON字符串,通过dataModel.deserialize(jsonString)将JSON字符串内存反序列化出模型信息,而存储主要就是主要就是针对JSON字符串进行操作。


    流程图

    2. LocalStorage

    先介绍最简单的存储方式LocalStorage,代码如下,几乎不用介绍就是Key-Value的简单键值对存储结构,Web Storage除了localStorage的持久性存储外,还有针对本次回话的sessionStorage方式,一般情况下localStorage较为常用。
    这两种存储方式的API也一样,详细说明可以自行百度。
    获取某一条:localStorage.getItem("key")、sessionStorage.getItem("key");
    存储某一条:localStorage.setItem("key", value)、sessionStorage.setItem("key", value);
    删除某一条:localStorage.removeItem("key")、sessionStorage.removeItem("key");
    删除所有:localStorage.clear()、sessionStorage.clear();

    localStorage和sessionStorage

    3. Cookie

    最古老的存储方式为Cookie,本例中我只能保存一个图元的信息,这种存储方式存储内容很有限,只适合做简单信息存储,存取接口设计得极其反人类,为了介绍HTML5存储方案的完整性我顺便把他给列上:

    function getCookieValue(name) {
       if (document.cookie.length > 0) {
         var start = document.cookie.indexOf(name + "=");
         if (start !== -1) {
           start = start + name.length + 1;
           var end = document.cookie.indexOf(";", start);
           if (end === -1) end = document.cookie.length;
           return unescape(document.cookie.substring(start, end));
         }
       }
       return '';
    }
    
    function save(dataModel) {
       var value = dataModel.serialize();
       document.cookie = 'DataModel=' + escape(value);
       document.cookie = 'DataCount=' + dataModel.size(); 
       console.log(dataModel.size() + ' datas are saved');
       return value;
    }
    
    function restore(dataModel){ 
       var value = getCookieValue('DataModel');
       if (value) {
         dataModel.deserialize(value);
         console.log(getCookieValue('DataCount') + ' datas are restored');
         return value;
       } 
       return '';
    }
    
    function clear() {
       if(getCookieValue('DataModel')){
         console.log(getCookieValue('DataCount') + ' datas are cleared');
         document.cookie = "DataModel=; expires=Thu, 01 Jan 1970 00:00:00 UTC";
         document.cookie = "DataCount=; expires=Thu, 01 Jan 1970 00:00:00 UTC"; 
       }
    }
    

    4. Indexed Database API

    如今比较实用强大的存储方式为Indexed Database API,IndexedDB可以存储结构对象,可构建key和index的索引方式查找,目前各浏览器的已经逐渐支持IndexedDB的存储方式,其使用代码如下,需注意IndexedDB的很多操作接口类似NodeJS的异步回调方式,特别是查询时连cursor的continue都是异步再次回调onsuccess函数的操作方式,因此和NodeJS一样使用上不如同步的代码容易。

    request = indexedDB.open("DataModel");
    request.onupgradeneeded = function() { 
       db = request.result;
       var store = db.createObjectStore("meters", {keyPath: "id"});
       store.createIndex("by_tag", "tag", {unique: true});
       store.createIndex("by_name", "name"); 
    };
    
    request.onsuccess = function() {
       db = request.result;
    };
    
    function save(dataModel) {
       var tx = db.transaction("meters", "readwrite");
       var store = tx.objectStore("meters");
       dataModel.each(function(data){
         store.put({
           id: data.getId(),
           tag: data.getTag(),
           name: data.getName(),
           meterValue: data.a('meter.value'),
           meterAngle: data.a('meter.angle'),
           p3: data.p3(),
           r3: data.r3(),
           s3: data.s3()
         }); 
       }); 
       tx.oncomplete = function() {
         console.log(dataModel.size() + ' datas are saved');
       }; 
       return dataModel.serialize();
    }
    
    function restore(dataModel) { 
       var tx = db.transaction("meters", "readonly");
       var store = tx.objectStore("meters");
       var req = store.openCursor(); 
       var nodes = [];
       req.onsuccess = function() { 
         var res = req.result;
         if (res) {
           var value = res.value;
           var node = createNode();
           node.setId(value.id);
           node.setTag(value.tag);
           node.setName(value.name); 
           node.a({
             'meter.value': value.meterValue,
             'meter.angle': value.meterAngle
           });
           node.p3(value.p3); 
           node.r3(value.r3);
           node.s3(value.s3);
           nodes.push(node); 
           res.continue();
         } else {
           if(nodes.length){
             dataModel.clear();
             nodes.forEach(function(node) {
               dataModel.add(node); 
             });
             console.log(dataModel.size() + ' datas are restored');
           } 
         } 
       }; 
       return '';
    }
    
    function clear() {
       var tx = db.transaction("meters", "readwrite");
       var store = tx.objectStore("meters");
       var req = store.openCursor();
       var count = 0;
       req.onsuccess = function(event) { 
         var res = event.target.result;
         if(res){
            store.delete(res.value.id);
            res.continue();
            count++;
         } else {
            console.log(count + ' datas are cleared');
         } 
       };
    }
    

    5. FileSystem API

    最后是FileSystem API相当于操作本地文件的存储方式,目前支持浏览器不多,其接口标准也在发展制定变化中,例如在我写这个代码时大部分文献使用的webkitStorageInfo已被navigator.webkitPersistentStorage和navigator.webkitTemporaryStorage替代,存储的文件可通过filesystem的URL方式在chrome浏览器中查找到,甚至可通过filesy类似目录的访问,因此也可以动态生成图片到本地文件,然后通过filesystem:http:***的URL方式直接赋值给img的html元素的src访问,因此本地存储打开了一扇新的门,相信以后会冒出更多稀奇古怪的奇葩应用。

    navigator.webkitPersistentStorage.queryUsageAndQuota(function (usage, quota) {
       console.log('PERSISTENT: ' + usage + '/' + quota + ' - ' + usage / quota + '%');
    });
    
    navigator.webkitPersistentStorage.requestQuota(2 * 1024 * 1024, function (grantedBytes) {
       window.webkitRequestFileSystem(window.PERSISTENT, grantedBytes, function (fs) {
          window.fs = fs;
       });
    });
    
    function save(dataModel) {
       var value = dataModel.serialize();
       fs.root.getFile('meters.txt', {create: true}, function (fileEntry) {
         console.log(fileEntry.toURL());
         fileEntry.createWriter(function (fileWriter) {
           fileWriter.onwriteend = function () {
             console.log(dataModel.size() + ' datas are saved');
           };
           var blob = new Blob([value], {type: 'text/plain'});
           fileWriter.write(blob);
         });
       });
       return value;
    }
    
    function restore(dataModel) {
       fs.root.getFile('meters.txt', {}, function (fileEntry) {
         fileEntry.file(function (file) {
           var reader = new FileReader();
           reader.onloadend = function (e) {
             dataModel.clear();
             dataModel.deserialize(reader.result);
             console.log(dataModel.size() + ' datas are restored');
           };
           reader.readAsText(file);
         });
       });
       return '';
    }
    
    function clear() {
       fs.root.getFile('meters.txt', {create: false}, function(fileEntry) {
         fileEntry.remove(function() {
           console.log(fileEntry.toURL() + ' is removed');
         });
       }); 
    }
    
    FileSystem API

    6. 其他

    Browser-Side的存储方式还在快速的发展中,其实除了以上几种外还有Application Cache,相信将来还会有新秀出现,虽然“云”是大趋势,但客户端并非要走极端的“瘦”方案,这么多年冒出了这么多客户端存储方式,说明让客户端更强大的市场需求是强烈的,当然目前动荡阶段苦逼的是客户端程序员,除了要适配Mouse和Touch,还要适配各种屏,如今还得考虑适配各种存储,希望本文能在大家选型客户端存储方案时有点帮助。

    关注公众号【grain先森】,回复关键词 【18福利】,获取为你准备的年终福利,更多关键词玩法期待你的探索~

    相关文章

      网友评论

        本文标题:H5的离线存储方案

        本文链接:https://www.haomeiwen.com/subject/orqksqtx.html