我们将以下数据从浏览器发送到服务器,除了JSON之外,对数据进行序列化/反序列化的最佳方法是什么?
我们最初将数据保存在客户端浏览器中,然后在常规检查点将其发送到服务器。由于数据的大小,发送数据时会占用大量浏览器内存以及网络。我们希望减少发送到服务器的数据的大小,因为每个对象的keys
大多数都是相同的,但是values
有所变化。
[
{
"range":{
"sLineNumber":3,
"sColumn":3,
"eLineNumber":3,
"eColumn":3
},
"rLength":0,
"text":"\n",
"rOffset":4,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":4,
"sColumn":1,
"eLineNumber":4,
"eColumn":1
},
"rLength":0,
"text":"\n",
"rOffset":5,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":5,
"sColumn":1,
"eLineNumber":5,
"eColumn":1
},
"rLength":0,
"text":"\n",
"rOffset":6,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":1,
"eLineNumber":6,
"eColumn":1
},
"rLength":0,
"text":"f",
"rOffset":7,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":2,
"eLineNumber":6,
"eColumn":2
},
"rLength":0,
"text":"a",
"rOffset":8,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":3,
"eLineNumber":6,
"eColumn":3
},
"rLength":0,
"text":"s",
"rOffset":9,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":4,
"eLineNumber":6,
"eColumn":4
},
"rLength":0,
"text":"d",
"rOffset":10,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":5,
"eLineNumber":6,
"eColumn":5
},
"rLength":0,
"text":"f",
"rOffset":11,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":6,
"eLineNumber":6,
"eColumn":6
},
"rLength":0,
"text":"a",
"rOffset":12,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":7,
"eLineNumber":6,
"eColumn":7
},
"rLength":0,
"text":"s",
"rOffset":13,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":8,
"eLineNumber":6,
"eColumn":8
},
"rLength":0,
"text":"f",
"rOffset":14,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":9,
"eLineNumber":6,
"eColumn":9
},
"rLength":0,
"text":"s",
"rOffset":15,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":10,
"eLineNumber":6,
"eColumn":10
},
"rLength":0,
"text":"a",
"rOffset":16,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":11,
"eLineNumber":6,
"eColumn":11
},
"rLength":0,
"text":"f",
"rOffset":17,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":12,
"eLineNumber":6,
"eColumn":12
},
"rLength":0,
"text":"s",
"rOffset":18,
"rMoveMarkers":false
}
]
我们认为的一种方法是将它们作为不带键的数组发送,因为我们知道每个key
的位置。不确定是否有任何可用于此转换的软件包。
答案 0 :(得分:4)
我们希望减少发送到服务器的数据的大小,因为每个对象的
keys
大部分都是相同的,但是values
有所变化。
如果您将数据视为表格,则可以将每一列表示为对象属性,并在数组中包含行值,如下所示:
{
"sLineNumber": [3, 4, /* ... */ ],
"sColumn": [3, 1, /* ... */ ],
"eLineNumber": [3, 4, /* ... */ ],
"eColumn": [3, 1, /* ... */ ],
"rLength": [0, 0, /* ... */ ],
"text": ["\n", "\n", /* ... */ ],
"rOffset": [4, 5, /* ... */ ],
"rMoveMarkers":[false, false, /* ... */ ]
}
此结构保留所有属性名称("range"
除外),并且内存效率更高。
数据仍然可以序列化为JSON,大小仅为原始结构的25%。
在1
中使用整数(0
和true
)代替布尔值(false
和"rMoveMarkers"
,可以进一步减小大小。< / p>
快速且肮脏的代码可用于重组以下代码段中的数据:
var data = [
{
"range":{
"sLineNumber":3,
"sColumn":3,
"eLineNumber":3,
"eColumn":3
},
"rLength":0,
"text":"\n",
"rOffset":4,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":4,
"sColumn":1,
"eLineNumber":4,
"eColumn":1
},
"rLength":0,
"text":"\n",
"rOffset":5,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":5,
"sColumn":1,
"eLineNumber":5,
"eColumn":1
},
"rLength":0,
"text":"\n",
"rOffset":6,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":1,
"eLineNumber":6,
"eColumn":1
},
"rLength":0,
"text":"f",
"rOffset":7,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":2,
"eLineNumber":6,
"eColumn":2
},
"rLength":0,
"text":"a",
"rOffset":8,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":3,
"eLineNumber":6,
"eColumn":3
},
"rLength":0,
"text":"s",
"rOffset":9,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":4,
"eLineNumber":6,
"eColumn":4
},
"rLength":0,
"text":"d",
"rOffset":10,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":5,
"eLineNumber":6,
"eColumn":5
},
"rLength":0,
"text":"f",
"rOffset":11,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":6,
"eLineNumber":6,
"eColumn":6
},
"rLength":0,
"text":"a",
"rOffset":12,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":7,
"eLineNumber":6,
"eColumn":7
},
"rLength":0,
"text":"s",
"rOffset":13,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":8,
"eLineNumber":6,
"eColumn":8
},
"rLength":0,
"text":"f",
"rOffset":14,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":9,
"eLineNumber":6,
"eColumn":9
},
"rLength":0,
"text":"s",
"rOffset":15,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":10,
"eLineNumber":6,
"eColumn":10
},
"rLength":0,
"text":"a",
"rOffset":16,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":11,
"eLineNumber":6,
"eColumn":11
},
"rLength":0,
"text":"f",
"rOffset":17,
"rMoveMarkers":false
},
{
"range":{
"sLineNumber":6,
"sColumn":12,
"eLineNumber":6,
"eColumn":12
},
"rLength":0,
"text":"s",
"rOffset":18,
"rMoveMarkers":false
}
];
function transform(data){
var transformed = {};
['rLength', 'text', 'rOffset', 'rMoveMarkers']
.map(x => transformed[x] = data.map(y => y[x]));
['sLineNumber', 'sColumn', 'eLineNumber', 'eColumn']
.map(x => transformed[x] = data.map(y => y.range[x]));
return transformed;
}
var originalLength = JSON.stringify(data).length;
var transformedLength = JSON.stringify(transform(data)).length;
console.log(
'Reduced to ' +
(100 * transformedLength / originalLength).toFixed(1) +
'% size of original, from ' + originalLength + ' characters to ' +
transformedLength + ' characters.'
);
console.log(transform(data));
我们认为的一种方法是将它们作为不带键的数组发送,因为我们知道每个
key
的位置。不确定是否有任何可用于此转换的软件包。
可以将数据简化为二维数组:
function transform(data) {
return ['rLength', 'text', 'rOffset', 'rMoveMarkers']
.map(x => data.map(y => y[x]))
.concat(
['sLineNumber', 'sColumn', 'eLineNumber', 'eColumn']
.map(x => data.map(y => y.range[x]))
);
}
请注意,与上面的数据结构相比,放下键(属性名称)仅会减少一点点,而这又使跟踪错误或解决任何问题变得更加困难,因为您必须确保不要无意间混淆哪个数组属于哪个键。
下面的代码段中的演示代码:
var data = [{
"range": {
"sLineNumber": 3,
"sColumn": 3,
"eLineNumber": 3,
"eColumn": 3
},
"rLength": 0,
"text": "\n",
"rOffset": 4,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 4,
"sColumn": 1,
"eLineNumber": 4,
"eColumn": 1
},
"rLength": 0,
"text": "\n",
"rOffset": 5,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 5,
"sColumn": 1,
"eLineNumber": 5,
"eColumn": 1
},
"rLength": 0,
"text": "\n",
"rOffset": 6,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 1,
"eLineNumber": 6,
"eColumn": 1
},
"rLength": 0,
"text": "f",
"rOffset": 7,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 2,
"eLineNumber": 6,
"eColumn": 2
},
"rLength": 0,
"text": "a",
"rOffset": 8,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 3,
"eLineNumber": 6,
"eColumn": 3
},
"rLength": 0,
"text": "s",
"rOffset": 9,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 4,
"eLineNumber": 6,
"eColumn": 4
},
"rLength": 0,
"text": "d",
"rOffset": 10,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 5,
"eLineNumber": 6,
"eColumn": 5
},
"rLength": 0,
"text": "f",
"rOffset": 11,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 6,
"eLineNumber": 6,
"eColumn": 6
},
"rLength": 0,
"text": "a",
"rOffset": 12,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 7,
"eLineNumber": 6,
"eColumn": 7
},
"rLength": 0,
"text": "s",
"rOffset": 13,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 8,
"eLineNumber": 6,
"eColumn": 8
},
"rLength": 0,
"text": "f",
"rOffset": 14,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 9,
"eLineNumber": 6,
"eColumn": 9
},
"rLength": 0,
"text": "s",
"rOffset": 15,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 10,
"eLineNumber": 6,
"eColumn": 10
},
"rLength": 0,
"text": "a",
"rOffset": 16,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 11,
"eLineNumber": 6,
"eColumn": 11
},
"rLength": 0,
"text": "f",
"rOffset": 17,
"rMoveMarkers": false
},
{
"range": {
"sLineNumber": 6,
"sColumn": 12,
"eLineNumber": 6,
"eColumn": 12
},
"rLength": 0,
"text": "s",
"rOffset": 18,
"rMoveMarkers": false
}
];
function transform(data) {
return ['rLength', 'text', 'rOffset', 'rMoveMarkers']
.map(x => data.map(y => y[x]))
.concat(
['sLineNumber', 'sColumn', 'eLineNumber', 'eColumn']
.map(x => data.map(y => y.range[x]))
);
}
var originalLength = JSON.stringify(data).length;
var transformedLength = JSON.stringify(transform(data)).length;
console.log(
'Reduced to ' +
(100 * transformedLength / originalLength).toFixed(1) +
'% size of original, from ' + originalLength + ' characters to ' +
transformedLength + ' characters.'
);
console.log(transform(data));
答案 1 :(得分:3)
激活gzip压缩并将其作为不带键的数组发送。
答案 2 :(得分:1)
我建议创建到服务器的WebSocket连接,然后在数据创建后立即将其推送。如果您对JS进行了简化,那么您应该很容易就能每秒发送1,000个这些对象。
签出https://socket.io/,这是使用WebSockets的简便方法。
另一个限制因素将是您的浏览器代码。如果您使用React来确保停止它,从而使需求重新出现,那么您可能还需要优化它。
答案 3 :(得分:0)
以下几种方法可以实现最佳压缩效果:
express.js
的{{3}}。应该与其他实用程序一起使用。此外,如果您可以自己更新数据,则可以:
{
"keys": ["sLineNumber", "sColumn", "eLineNumber", ..., "rMoveMarkers"],
"values": [
[3, 4, ...],
[3, 1, ...],
[3, 4, ...],
...
[false, false, ...],
]
}
{
"sLineNumber": [3, 4, ...],
"sColumn": [3, 1, ...],
"eLineNumber": [3, 4, ...],
...
"rMoveMarkers":[false, false, ...]
}
与gZip一起使用-在大多数情况下应该足够了。