• HTML5五种客户端离线存储方案


    最近折腾HTML5游戏需要离线存储功能,便把目前可用的几种HTML5存储方式研究了下,基于HT for Web写了个综合的实例,分别利用了Cookie、WebStorage、IndexedDB以及FileSystem四种本地离线存储方式,对燃气监控系统的表计位置、朝向、开关以及表值等信息做了CURD的存取操作。

    http://www.hightopo.com/guide/guide/core/serialization/examples/example_exportimport.html

    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.

    Screen Shot 2014-12-22 at 1.39.12 AM

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

    先介绍最简单的存储方式LocalStorage,代码如下,几乎不用介绍就是Key-Value的简单键值对存储结构,Web Storage除了localStorage的持久性存储外,还有针对本次回话的sessionStorage方式,一般情况下localStorage较为常用,更多可参考 http://www.w3.org/TR/webstorage/

    function save(dataModel){
        var value = dataModel.serialize();
        window.localStorage['DataModel'] = value;
        window.localStorage['DataCount'] = dataModel.size();
        console.log(dataModel.size() + ' datas are saved');
        return value;
    }
    function restore(dataModel){  
        var value = window.localStorage['DataModel'];
        if(value){
            dataModel.deserialize(value);
            console.log(window.localStorage['DataCount'] + ' datas are restored');
            return value;
        }    
        return '';
    }
    function clear(){
        if(window.localStorage['DataModel']){
            console.log(window.localStorage['DataCount'] + ' datas are cleared');
            delete window.localStorage['DataModel'];
            delete window.localStorage['DataCount'];         
        }   
    }

    最古老的存储方式为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";   
        }
    }

    如今比较实用强大的存储方式为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');
            }         
        };
    
    }

    最后是FileSystem API相当于操作本地文件的存储方式,目前支持浏览器不多,其接口标准也在发展制定变化中,例如在我写这个代码时大部分文献使用的webkitStorageInfo已被navigator.webkitPersistentStorage和navigator.webkitTemporaryStorage替代,存储的文件可通过filesystem:http://www.hightopo.com/persistent/meters.txt’的URL方式在chrome浏览器中查找到,甚至可通过filesystem:http://www.hightopo.com/persistent/类似目录的访问,因此也可以动态生成图片到本地文件,然后通过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');
            });
        });    
    }

    Screen Shot 2014-12-22 at 12.53.48 AM

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

    http://www.hightopo.com/guide/guide/core/serialization/examples/example_exportimport.html

  • 相关阅读:
    基于s5pv210的uboot总结
    QQ群笔记
    设计模式----适配器模式
    设计模式----桥接模式
    设计模式----建造者模式
    设计模式----原型模式
    设计模式----单例模式
    设计模式----工厂方法模式
    设计模式----设计原则
    JUnit单元测试--小试牛刀
  • 原文地址:https://www.cnblogs.com/xhload3d/p/4941750.html
Copyright © 2020-2023  润新知