ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

深入JSONC源码:按键映射压缩算法原理逐行解析

深入JSONC源码:按键映射压缩算法原理逐行解析 深入JSONC源码按键映射压缩算法原理逐行解析【免费下载链接】JSONCJSON compressor and decompressor项目地址: https://gitcode.com/gh_mirrors/json/JSONC在网络请求的世界里数据量每多一分用户体验就慢一秒。当浏览器需要向服务器发送大量 JSON 数据时冗长的字段名往往占据了传输体积的大半。JSONC正是一款专为解决此问题而生的 JSON 压缩与解压工具库它的核心秘密就是按键映射压缩算法——把长长的键名换成单个字符再附带一张对照表轻松还原。本文不聊复杂理论带你直接走进 src/JSONC.js 源码逐行看懂这套精妙的按键映射压缩算法原理。一、JSONC 是什么一套 JSON 压缩与解压的轻量方案JSONCJSON Compressor由JSONC.compress/JSONC.decompress与JSONC.pack/JSONC.unpack两组 API 组成按键映射压缩compress用短键替换长键压缩率可达7.5% ~ 32.81%Gzip 深度压缩pack在此基础上叠加 gzip Base64让数据体积再降一档。整个库零依赖、源码只有三百多行非常适合浏览器端直传数据、接口瘦身等场景。项目还提供了 Benchmark 演示目录 与 PHP 端解压实现方便前后端配合使用。二、核心思路按键映射压缩算法究竟做了什么看代码前先建立直觉。假设原始 JSON 长这样{ userName: Tom, userEmail: tomx.com }userName、userEmail各 8~10 个字符但字段名在大量数据里会重复出现千百次。按键映射压缩算法的思路很直白遍历整个 JSON收集所有不重复的键名给每个键名分配一个超短代号A、B、C…用代号替换原键名同时把对照关系存进一个_属性里解压时读取_把代号反向替换回原名即可。压缩后的结果类似{ _: { A: userName, B: userEmail }, A: Tom, B: tomx.com }。这就是按键映射压缩算法的全貌接下来逐行拆解实现。三、短键从哪来解析_numberToKey代号生成器先看最有趣的部分——如何给第 N 个键生成短代号见 src/JSONC.jsvar sKeys ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/_!?()*; while (currentChar totalChar) { aArr.push(sKeys.charCodeAt((currentChar % totalChar) offset)); currentChar Math.floor(currentChar / totalChar - 1); } aArr.push(sKeys.charCodeAt(currentChar offset)); return aArr.reverse();这里用了一个 66 字符的字母表大小写字母 数字 特殊符号。_numberToKey本质上是一个66 进制转换器序号 0 →A、25 →Z、66 →BA以此类推。这样理论上能表示66 66² 66³…个键名且每个键名都极短。生成的是 ASCII 码数组再由_getSpecialKey用String.fromCharCode还原成字符串。四、键名怎么收集解析_getKeys遍历器有了代号生成器下一步就是收集所有键名对应 src/JSONC.jsfor (sKey in json) { if (json.hasOwnProperty(sKey)) { oItem json[sKey]; if (_isObject(oItem) || _isArray(oItem)) { aKeys aKeys.concat(unique(_getKeys(oItem, aKeys))); // 递归深入嵌套 } if (isNaN(Number(sKey))) { // 跳过纯数字下标数组索引 if (!contains(aKeys, sKey)) { _nCode 1; aKeys.push([_getSpecialKey(_numberToKey(_nCode)), sKey]); } } } }几个值得注意的设计点递归遍历遇到对象或数组就深入一层嵌套再深也能收集到跳过数字键数组的0、1、2索引不参与映射避免无意义开销去重借助unique与contains保证同一键名只分配一次代号静态计数器_nCode每次compress前会重置为-1保证代号从A重新分配。五、压缩主流程_compressOther如何完成键替换键收集完毕真正的换装发生在_compressOther见 src/JSONC.jsoKeys _biDimensionalArrayToObject(aKeys); // 二维数组转映射表 str JSON.stringify(json); // 序列化为字符串 for (nIndex 0; nIndex nLenKeys; nIndex) { aKey aKeys[nIndex]; str str.replace(new RegExp(escapeRegExp( aKey[1] ), g), aKey[0] ); // 全局替换键名 } obj JSON.parse(str); obj._ oKeys; // 附上映射表 return obj;流程相当巧妙先把 JSON序列化成字符串用正则把所有长键名替换为短代号再反序列化回对象最后把映射表挂到_属性上。escapeRegExp负责转义键名里的特殊字符避免正则误伤。压缩后的体积如何实测数据可以参考 Benchmark 目录下的 demo原始 19031 字节的对象经按键映射压缩后仅 12787 字节压缩率高达 32.81%。六、反向还原_decompressOther的解压逻辑解压是压缩的镜像操作见 src/JSONC.jsoKeys JSON.parse(JSON.stringify(jsonCopy._)); // 取出映射表 delete jsonCopy._; // 移除 _ 属性 str JSON.stringify(jsonCopy); for (sKey in oKeys) { str str.replace(new RegExp( sKey , g), oKeys[sKey] ); } return JSON.parse(str); // 还原为原始 JSON逻辑一目了然先拷贝一份数据避免污染原对象取出_映射表并删除再把字符串里的短代号批量替换回原名。注意compress/decompress对数组有专门分支_compressArray/_decompressArray会逐个元素递归处理保证数组套对象的场景也能正确压缩还原。这一点在 test/JSONC.js 的测试用例里有完整覆盖。七、更进一步pack / unpack 与 gzip 的强强联合按键映射压缩已经足够惊艳但 JSONC 还能再进一步。JSONC.pack在 src/JSONC.js 中把压缩后的 JSON 序列化后交给gziplevel 9 最大压缩再用Base64编码JSONC.unpack则反向解包。由于 Base64 编码对 URL 安全浏览器向服务器直传 gzip 数据也能畅通无阻服务端只需配合 GzipJSON.php 中十几行的gzinflate就能解压还原。八、压缩效果实测一组来自官方 Benchmark 的数据上图 Benchmark 展示了两种典型对象在 6 种处理方式下的传输体积对比数据来自 Benchmark/Benchmark_Results.png处理方式Obj2 发送体积相比最重方案的提升simple json stringify不压缩265800%json stringify with base64253834.5%pack gzip without base641690336.41%pack gzip with base64874367.11%pack gzip and compress with base64959563.9%结论很明显按键映射压缩 gzip Base64的组合拳能把发送体积砍掉约64% ~ 67%性能提升立竿见影。九、小结按键映射压缩算法的适用场景最后划一下重点✅适合键名长、字段重复多、数据量大比如列表、表格数据的 JSON⚠️注意小对象反而可能因为附带_映射表而变大压缩率区间为 7.5% ~ 32.81%用前建议先实测扩展压缩后用pack走 gzip Base64 通道是浏览器直传大数据的最优解。这套按键映射压缩算法代码不过百行却蕴含了用映射表换取体积的精妙思想。想亲手实验的话直接运行项目里的 test/JSONC.js 测试用例或打开 Benchmark 演示页 感受压缩前后的体积差异。看懂它你就掌握了 JSON 瘦身的一把利器。【免费下载链接】JSONCJSON compressor and decompressor项目地址: https://gitcode.com/gh_mirrors/json/JSONC创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表