使用cookie作对象持久化
个人首先是非常不推荐使用cookie作对象持久化的,因为cookie在每次request请求中都会带上,无形就增加了请求的大小。
如果对cookie的domain没有管理好,问题会更大,如所有domain.com下的cookie,在你请求js.domain.com或img.domain.com也都会带上,但这些域下的cookie是毫无意义的;所以很多网站会使用其他域名如jsdomain.com或imgdomain.com以减小cookie对请求的开销。
已有的工具:jquery.jsoncookie.js(可参考http://lab.distilldesign.com/json-cookie/),这个插件依赖于jquery.cookie.js,如果浏览器不支持JSON的方法,你或许还需要一个json2.js。
那为什么不直接用这个插件,我们先看个例子:
对象: {id: 123, name: "mapping", test: "Hello World"}
先转成字符串,使用JSON.stringify: '{"id":123,"name":"mapping","test":"Hello World"}' length:48
再转成URI Encode,使用encodeURIComponent: '%7B%22id%22%3A123%2C%22name%22%3A%22mapping%22%2C%22test%22%3A%22Hello%20World%22%7D' length:84
可以看到经过转码后的json字符串长度几乎翻倍,是因为浏览器为了安全考虑,会将{、"、,等这些特殊符号进行转义编码。
如果使用上方插件必然会增加cookie的开销,那我们就需要尽量避免cookie的内容被转码,可以考虑使用-、_、.这些字符,使用"."可能会跟数据的小数点冲突,但实际情况多是用cookie记录id的整数,所以也可以考虑
CookieString = { setting: { groupfix: '_', childfix: '-', itemfix: '.' }, stringify: function(obj) { var t = this, groups = [], isArray = function(ar) { return Object.prototype.toString.call(ar) === '[object Array]'; }, o, items; if(isArray(obj)) { groups = obj; } else { for(o in obj) { if(obj.hasOwnProperty(o)) { items = obj[o]; if(isArray(obj[o])) { items = items.join(t.setting.itemfix); } groups.push(o + t.setting.childfix + items); } } } return groups.join(t.setting.groupfix); }, parse: function(str) { var t = this, groups = str.split(t.setting.groupfix), o, c, i, obj = false; if(str.indexOf(t.setting.childfix) !== -1) { obj = {}; } else { obj = []; } for(o in groups) { c = groups[o].split(t.setting.childfix); if(c[1] === undefined) { obj.push(c[0]); } else { i = c[1].split(t.setting.itemfix); obj[c[0]] = i.length === 1 ? i[0] : i; } } return obj; } };
来看一下测试结果,这里推荐使用qunit作为测试框架。tips:如果需要在页面中看到测试结果,记得加一个<div id="qunit"></div>的节点
test('CookieString.stringify', function() { equal(CookieString.stringify({1:[1,2,3], 2:4}), '1-1.2.3_2-4', 'stringify object'); equal(CookieString.stringify([1,2,3,4]), '1_2_3_4', 'stringify array'); }); test('CookieString.parse', function() { deepEqual(CookieString.parse('1-1.2.3_2-4'), {1:['1','2','3'], 2:'4'}, 'parse object'); deepEqual(CookieString.parse('1_2_3_4'), ['1','2','3','4'], 'parse object'); });
测试通过了^_^
对象已经可以成功转为字符串了,接下来可以借助jquery.cookie.js读写cookie;
慢着,事情还没有结束,这样子后端要解析cookie的值不会像转下json那么简单了,但如果在项目中约定好cookie的格式,后端写好解析该格式的公用库也会得心应手的。
ps:使用开源库确实可以节省不少开发时间,但也会增加很多额外开销;用和不用没有对错之分,只有合适与不合适,如果感觉不合适,那就自己乖乖写吧~~