Проблемы со сжатием в JavaScript
У меня есть объект, который я пытаюсь сжать. Это имеет форму
[
{
array
string
},
{
array
string
},
...
]
Массивы имеют длину не более 10–15, что очень мало по сравнению со строками (они имеют формат html, длиной около 170 тыс.). Строки, как правило, повторяются или имеют огромное количество совпадений. Таким образом, моя интуиция говорит мне, что сжатое значение должно быть значением сжатия 1 строки плюс немного больше.
Я JSON.stringify этого объекта и пытаюсь сжать.
Большинство библиотек сжатия плохо сжимали строки, так как сервер отправляет мне сжатую gzip версию 77 КБ, я знаю, что она может быть как минимум такой маленькой.
GZIP-JS
LZMA-JS
Сделал хорошую работу из 15 библиотек, которые я попробовал.
Проблема в том, что gzip-js является линейным по количеству строк. Но lzma делает это правильно, когда она только немного увеличивается в размерах.
Lzma-js (уровень 2), к сожалению, очень медленный (20 с против 1 с gzip) при сжатии 7 МБ (около 30 строк).
Существует ли какая-либо библиотека compressopn, которая примерно такая же быстрая, как gzip, но не масштабируется линейно на повторяющихся строках?
2 ответа
Пако был полезен для меня, попробуй:
Вместо использования строковых идентификаторов используйте byteArrays, как это делается здесь.
Получите pako.js, и вы можете распаковать byteArray следующим образом:
<html>
<head>
<title>Gunzipping binary gzipped string</title>
<script type="text/javascript" src="pako.js"></script>
<script type="text/javascript">
// Get datastream as Array, for example:
var charData = [31,139,8,0,0,0,0,0,0,3,5,193,219,13,0,16,16,4,192,86,214,151,102,52,33,110,35,66,108,226,60,218,55,147,164,238,24,173,19,143,241,18,85,27,58,203,57,46,29,25,198,34,163,193,247,106,179,134,15,50,167,173,148,48,0,0,0];
// Turn number array into byte-array
var binData = new Uint8Array(charData);
// Pako magic
var data = pako.inflate(binData);
// Convert gunzipped byteArray back to ascii string:
var strData = String.fromCharCode.apply(null, new Uint16Array(data));
// Output to console
console.log(strData);
</script>
</head>
<body>
Open up the developer console.
</body>
</html>
Работающий пример: http://jsfiddle.net/9yH7M/
В качестве альтернативы вы можете кодировать массив с помощью base64, прежде чем отправлять его, так как Array занимает много времени при отправке в формате JSON или XML. Расшифровать аналогично:
// Get some base64 encoded binary data from the server. Imagine we got this:
var b64Data = 'H4sIAAAAAAAAAwXB2w0AEBAEwFbWl2Y0IW4jQmziPNo3k6TuGK0Tj/ESVRs6yzkuHRnGIqPB92qzhg8yp62UMAAAAA==';
// Decode base64 (convert ascii to binary)
var strData = atob(b64Data);
// Convert binary string to character-number array
var charData = strData.split('').map(function(x){return x.charCodeAt(0);});
// Turn number array into byte-array
var binData = new Uint8Array(charData);
// Pako magic
var data = pako.inflate(binData);
// Convert gunzipped byteArray back to ascii string:
var strData = String.fromCharCode.apply(null, new Uint16Array(data));
// Output to console
console.log(strData);
Работающий пример: http://jsfiddle.net/9yH7M/1/
Для получения более подробной информации читайте документацию по pako API.
Используйте gzip-js lib с высоким уровнем сжатия
https://github.com/beatgammit/gzip-js
var gzip = require('gzip-js'),
options = {
level: 9,
name: 'hello-world.txt',
timestamp: parseInt(Date.now() / 1000, 10)
};
// out will be a JavaScript Array of bytes
var out = gzip.zip('Hello world', options);
Я нашел этот способ как минимально возможного размера с нормальной продолжительностью
А для алгоритма сжатия на основе LZ я думаю, что lz-string быстрее
проверьте это на вашем образце данных
https://github.com/pieroxy/lz-string