Лучший способ уменьшить объем данных объекта, передаваемых из браузера на сервер - PullRequest
2 голосов
/ 03 ноября 2019

У нас есть следующие данные, отправленные из браузера на сервер, каков наилучший способ сериализации / десериализации данных, отличных от 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. Не уверен, есть ли какой-либо пакет для этого преобразования.

Ответы [ 4 ]

3 голосов
/ 12 ноября 2019

Активируйте сжатие gzip и отправьте его в виде массива без ключей.

2 голосов
/ 12 ноября 2019

Мы хотим уменьшить размер данных, отправляемых на сервер, поскольку 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".

Быстрый и грязный код для реструктуризации данных в фрагменте ниже:

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));
0 голосов
/ 15 ноября 2019

Если вы хотите явно сжать JSON, вы можете использовать jsonpack . Работает в Node и браузере.

0 голосов
/ 15 ноября 2019

Я бы предложил создать соединение WebSocket с сервером, а затем передать данные поверх него, как только оно будет создано. Если ваш JS достаточно оптимизирован, вы легко сможете отправлять 1000 таких объектов в секунду.

Оформление заказа https://socket.io/, что является простым способом использования WebSockets.

Другим ограничивающим фактором будет код вашего браузера. Вероятно, вам также потребуется оптимизировать это, если вы используете React и убедитесь, что работаете над его остановкой, делая повторные запросы.

...