JavaScript: самый маленький JSON.stringify для Float32Array?

FireFox 46.0.1: Я использую стороннее программное обеспечение (easyrtc) для отправки 15КБ блоков Float32Arrays между узлами. Easyrtc настаивает на том, чтобы данные были в JSON-состоянии. К сожалению, JSON.stringify выдает строку более чем в два раза длиннее исходных данных: 16384 байта данных становится строкой длиной 35755. Ниже приведен мой тестовый код, за которым следует вывод на консоль. Что, если что-нибудь можно сделать, чтобы уменьшить размер stringify? Есть ли способ отправить только значения (без ключей)? Могу ли я использовать аргумент replacer для отправки только значений, и если да, то не нужно ли мне использовать replacer в соответствующем JSON.parse на принимающей стороне?

var g_testBufferNBytes = 4096 * 4;
var g_testBuffer = new ArrayBuffer(g_testBufferNBytes);
var g_testBufferView   = new Float32Array(g_testBuffer);
console.log("array byte length " + g_testBuffer.byteLength); 
console.log("view byte length " + g_testBufferView.byteLength);
var j = JSON.stringify(g_testBufferView);
console.log("j length " + j.length);
var newBuf = JSON.parse(j);
console.log("newBuf length " + Object.keys(newBuf).length);

КОНСОЛЬ: длина байта массива 16384 длина байта представления 16384 дж длина 35755 newBuf длина 4096

1 ответ

да

ES6: Предположим, что ваши данные находятся в let f32 = g_testBufferView (массив Float32Array)) - можно сохранить его как массив JSON как минимум четырьмя способами:

// code 
let f32json = JSON.stringify(f32);
let f32jsonArr = JSON.stringify(Array.from(f32));
let f32base64 = btoa(String.fromCharCode(...(new Uint8Array(f32.buffer))));
let f32base128 = ... // not trivial, look below


// decode
let df32json = new Float32Array(Object.values(JSON.parse(f32json))); 
let df32jsonArr = new Float32Array(JSON.parse(f32jsonArr));
let df32base64 = new Float32Array(new Uint8Array([...atob(f32base64)].map(c => c.charCodeAt(0))).buffer);
let df32base128 = ... // not trivial, look below

Обратите внимание, что Object.values возвращаемые значения отсортированы по числовым ключам (смотрите здесь).

Вот рабочий пример. Вы также можете использовать base128 do decode, но я не использую в этом примере (чтобы не усложнять его) - более подробно здесь.

Если твой Float32Array -f32имеет 4096 элементов, равных0.3затем:

  • f32имеет 16384 байта,
  • f32json(jот вашего вопроса) имеет 109483 байта (что в 6 раз больше, чемf32)
  • f32jsonArrимеет 81921 байт (что в 5 раз больше, чемf32)
  • f32base64имеет 21848 байт (что в 1,3 раза больше, чемf32)
  • f32base128имеет 18725 байт (чем<1,15 раза больше, чем f32) но chrome отправит запрос примерно в 2 раза больше (зависит от входных данных)

Если твойFloat32Array-f32имеет 4096 элементов равно целому числу от 1 до 9, то:

  • f32имеет 16384 байта -CONST,
  • f32json(jот вашего вопроса) имеет 35755 байт (что в 2 раза больше, чемf32)
  • f32jsonArr имеет 8193 байта (что в 2 раза меньше(sic!), чемf32)
  • f32base64 имеет 21848 байт - CONST(что примерно в 1,3 раза больше, чемf32)
  • f32base128 имеет 18725 байт - CONST (чем <1,15 раза больше, чем f32) но chrome отправит запрос примерно в 2 раза больше (зависит от входных данных)

Заключение

Наименьший результат, который не зависит от значений массива (размер результата постоянен), который мы получаем для f32base64 ~33% больше размера входного массива. За f32base128 - он содержит допустимый JSON (строка), который примерно на 15% больше, чем ввод, но chrome во время отправки увеличивает этот размер ( смотрите здесь - в разделе "обновление"). Так что используйте f32base64 - это, вероятно, самый маленький JSON, который вы можете получить без более сложных методов.

Другие вопросы по тегам