Я пишу веб-приложение, которому необходимо хранить данные JSON в небольшом серверном кеше фиксированного размера через AJAX (подумайте: Opensocial квоты). Я не контролирую сервер.
Мне нужно уменьшить размер хранимых данных, чтобы оставаться в рамках квоты на стороне сервера, и я надеялся, что смогу сжать строковый JSON в браузере перед отправкой его на сервер.
Однако я не могу найти много способов реализации Gzip в JavaScript. Любые предложения о том, как я могу сжать данные на стороне клиента перед их отправкой?
Правильная реализация этого, вероятно, непростая, поскольку javascript является однопоточным. Вероятно, придется сжимать партиями, используя setTimeout (), чтобы пользовательский интерфейс не блокировался при сжатии.
возможно, вы могли бы написать свой собственный алгоритм сжатия
@AugustLilleaas, теперь вы можете использовать для этого веб-воркеров :)



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Большинство браузеров могут распаковывать gzip на лету. Это может быть лучшим вариантом, чем реализация javascript.
Да, но мне нужно сжать данные на стороне клиента перед их отправкой ...
Я предполагаю, что обычная реализация сжатия JavaScript на стороне клиента будет очень дорогостоящей операцией с точки зрения времени обработки, в отличие от времени передачи еще нескольких HTTP-пакетов с несжатой полезной нагрузкой.
Проводили ли вы какое-либо тестирование, которое дало бы вам представление о том, сколько времени нужно сэкономить? Я имею в виду, что экономия полосы пропускания не может быть тем, что вам нужно, или может?
Мне нужно сохранить общий размер данных в пределах определенной квоты - размер важнее времени.
Хм ... Почему предел? Просто любопытно.
Что ж, вот взгляд Google на это: code.google.com/apis/opensocial/articles/… - Типичные квоты Opensocial составляют около 10 тысяч.
Понятно, спасибо за разъяснения.
В зависимости от того, насколько интенсивно сжатие, вы можете использовать веб-воркеров для выполнения задачи «за кулисами».
Вы можете использовать Java-апплет 1 пиксель на 1 пиксель, встроенный в страницу, и использовать его для сжатия.
Это не JavaScript, и клиентам потребуется среда выполнения Java, но она сделает то, что вам нужно.
Интересно, но по возможности я бы предпочел не включать апплет.
Я хотел бы добавить реальные варианты использования
Не лучшее решение, так как оно добавляет зависимость от Java. Кроме того, не все удосужились установить java - у некоторых сайт не будет работать. Лично у меня установлена java, так как она мне была нужна давным-давно, но я предпочитаю посещать сайты, которые не используют java.
Редактировать Кажется, есть лучшее решение LZW, которое правильно обрабатывает строки Unicode в http://pieroxy.net/blog/pages/lz-string/index.html (спасибо pieroxy в комментариях).
Я не знаю каких-либо реализаций gzip, но библиотека jsolait (сайт, похоже, исчез) имеет функции для сжатия / распаковки LZW. Код подпадает под LGPL.
// LZW-compress a string
function lzw_encode(s) {
var dict = {};
var data = (s + "").split("");
var out = [];
var currChar;
var phrase = data[0];
var code = 256;
for (var i=1; i<data.length; i++) {
currChar=data[i];
if (dict[phrase + currChar] != null) {
phrase += currChar;
}
else {
out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
dict[phrase + currChar] = code;
code++;
phrase=currChar;
}
}
out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
for (var i=0; i<out.length; i++) {
out[i] = String.fromCharCode(out[i]);
}
return out.join("");
}
// Decompress an LZW-encoded string
function lzw_decode(s) {
var dict = {};
var data = (s + "").split("");
var currChar = data[0];
var oldPhrase = currChar;
var out = [currChar];
var code = 256;
var phrase;
for (var i=1; i<data.length; i++) {
var currCode = data[i].charCodeAt(0);
if (currCode < 256) {
phrase = data[i];
}
else {
phrase = dict[currCode] ? dict[currCode] : (oldPhrase + currChar);
}
out.push(phrase);
currChar = phrase.charAt(0);
dict[code] = oldPhrase + currChar;
code++;
oldPhrase = phrase;
}
return out.join("");
}
Как может код быть LGPL, если алгоритм запатентован? Или срок действия всех патентов истек?
Согласно Википедии, срок действия патентов истек несколько лет назад. Хотя было бы неплохо проверить это.
LZW слишком стар, чтобы его все еще можно было запатентовать. Последние патенты истекли примерно в 2003 году. Есть множество бесплатных реализаций.
Я вижу по крайней мере две проблемы с приведенным выше кодом: 1) попробуйте сжать «Тест, чтобы сжать эти \ u0110 \ u0111 \ u0112 \ u0113 \ u0114 символы, отличные от ascii.», 2) Если код> 65535, об ошибке не сообщается.
И я забыл о третьем: результат кодирования находится в UTF-16. Ваше приложение справляется с этим?
Вот некоторая информация о том, как сжать Unicode: unicode.org/faq/compression.html. Похоже, это было не так уж и банально.
В zapper.hodgers.com/files/javascript/lzw_test/lzw.js есть другая реализация LZW, я не знаю, решает ли это какую-либо из вышеперечисленных проблем. Также см. Соответствующую запись в блоге: zapper.hodgers.com/labs/?p=90
FWIW - я не думаю, что реализация zapper.hodgers.com решает проблемы, описанные выше. Он отлично работал с «обычным старым ASCII», но когда я попробовал его на строке, сгенерированной, например, методом toDataUrl () холста HTML, сжатая, а затем распакованная строка не соответствовала оригиналу. Кто-нибудь реализовал сжатие JavaScript и декомпрессии таким образом, чтобы решить проблемы, указанные выше. и может справиться с производительностью со строками длиной примерно до 500 КБ - я понимаю, что это сложная задача!
@Sam - попробуйте utf8_encode (lzw_encode (my_string)). Вот кодировщик UTF8 в Javascript: farhadi.ir/works/utf8.
Вот реализации на 21 разных языках. rosettacode.org/wiki/LZW_compression написано, что он находится в общественном достоянии с 2004 года.
Кто-нибудь написал алгоритм сжатия, который еще нормально работает?
Мне не удалось найти библиотеку jsolait по ссылке, могу ли я просто использовать код ответа в моем бесплатном приложении для веб-сайта?
@simo Похоже, что сайт отключили (по крайней мере, контент). Да, LGPL позволяет использовать код как есть в вашем приложении.
@some Я только что выпустил небольшую библиотеку, исправляющую именно те проблемы, которые вы здесь указываете: pieroxy.net/blog/pages/lz-string/index.html
@pieroxy Спасибо, добавил ссылку на ваш сайт.
@ Мэтью Крамли, спасибо. Я использую библиотеку для самодельного RSS-ридера, и она кажется довольно стабильной. Я сжал (и успешно распаковал) несколько десятков мегабайт, и никаких проблем не возникло. Я уже подумываю добавить немного Хаффмана для правильного кодирования токенов, сгенерированных LZW, но мне нравится его скорость, поэтому я пока не знаю, куда я собираюсь пойти с этим.
Красиво - jsfiddle.net/lordloh/uJj7d
в моем тесте он работал некорректно - jsfiddle.net/4rh4js8h/1
@ hienbt88 Похоже, вы столкнулись с проблемой Unicode со вторым знаком «-», который не является обычным дефисом. Я бы попробовал код Pieroxy, который должен уметь обрабатывать символы, отличные от ASCII.
Вот некоторые другие алгоритмы сжатия, реализованные в Javascript:
эта реализация LZMA требует BrowserPlus (расширение браузера) и не выглядит чистым Javascript
эта реализация LZ77 больше не доступна, и, по крайней мере, ее версия Python (опубликованная на той же странице) была неправильной для довольно простых входных данных.
geocities мертв, обновлю ссылку
Это довольно близко к тому, что я хочу. гугл тоже обновится здесь
Я не тестировал, но есть реализация ZIP для javascript, которая называется JSZip:
Это zip, а не gzip, и он использует pako под капотом. Разница в том, что у zip есть метаданные информации о файле.
Я перенес реализацию LZMA из модуля GWT в автономный JavaScript. Он называется LZMA-JS.
у вас есть совместимый модуль php для этого?
У меня была другая проблема, я хотел кодировать данные не в gzip, а в декодировать сжатые данные. Я запускаю код javascript вне браузера, поэтому мне нужно декодировать его с помощью javascript чистый.
Это заняло у меня некоторое время, но я обнаружил, что в библиотеке JSXGraph есть способ читать сжатые данные.
Вот где я нашел библиотеку: http://jsxgraph.uni-bayreuth.de/wp/2009/09/29/jsxcompressor-zlib-compressed-javascript-code/ Есть даже отдельная утилита, которая может это сделать, JSXCompressor, а код лицензирован LGPL.
Просто включите файл jsxcompressor.js в свой проект, и тогда вы сможете читать данные в формате gzip в кодировке base 64:
<!doctype html>
</head>
<title>Test gzip decompression page</title>
<script src = "jsxcompressor.js"></script>
</head>
<body>
<script>
document.write(JXG.decompress('<?php
echo base64_encode(gzencode("Try not. Do, or do not. There is no try."));
?>'));
</script>
</html>
Я понимаю, что это не то, что вы хотели, но я все равно отвечаю здесь, потому что подозреваю, что это поможет некоторым людям.
Большое спасибо за то, что все еще поделились. Это именно то, что мне было нужно. Вы, вероятно, сэкономили мне часы безуспешных поисков, которых я действительно не могу сэкономить. +1
Интересно, почему его называют «компрессором», если это некомпрессор. ржу не могу
почти 5 лет спустя, все еще полезно. Спасибо. Я выгружаю большой JSON прямо на страницу, а не AJAX. предварительно сжимая его с помощью PHP и распаковывая обратно на стороне клиента JavaScript - я экономлю часть накладных расходов.
Нужен ли нам бит <?php..? .. Я спрашиваю, потому что он передается в метод decompress.
я получаю 14:16:28.512 TypeError: e.replace is not a function[Weitere Informationen] jsxcompressor.min.js:19:12201
БЛАГОДАРЮ ВАС! Очень помогло, 2 дня искал решение! Еще раз большое спасибо ...
Мы только что выпустили пакет pako https://github.com/nodeca/pako, перенос zlib на javascript. Я думаю, что это самая быстрая js-реализация deflate / inflate / gzip / ungzip. Кроме того, он имеет демократическую лицензию MIT. Pako поддерживает все параметры zlib, и его результаты бинарно идентичны.
Пример:
var inflate = require('pako/lib/inflate').inflate;
var text = inflate(zipped, {to: 'string'});
Предоставьте пример на стороне клиента для декодирования строк, сжатых с помощью gzip.
var inflate = require('pako/lib/inflate').inflate; var text = inflate(zipped, {to: 'string'}); @Redsandro, вот как я использую пако.
Этот пример на стороне клиента бросает incorrect header check
Вы отправляете его вверх на сервер. Вот почему существуют понятия «загрузка» и «загрузка». Может быть, поэтому вы получаете ответы, в которых говорится, что «сервер может это сделать».