Реализация JavaScript в Gzip [закрыто]


208

Я пишу веб-приложение, которое должно хранить данные JSON в небольшом серверном кэше фиксированного размера через AJAX (подумайте: квоты Opensocial ). У меня нет контроля над сервером.

Мне нужно уменьшить размер хранимых данных, чтобы они не выходили за пределы квоты на стороне сервера, и я надеялся получить возможность сжать зашифрованный JSON в браузере перед его отправкой на сервер.

Однако я не могу найти много способов реализации Gzip на JavaScript. Любые предложения о том, как я могу сжать данные на стороне клиента перед отправкой?


6
Вы отправляете его на сервер. Вот почему существуют понятия «загрузка» и «загрузка». Возможно, именно поэтому вы получаете ответы, в которых говорится, что «сервер может это сделать».
Томалак

3
Правильная реализация этого, вероятно, сложно, так как JavaScript является однопоточным. Вероятно, придется сжимать пакетами, используя setTimeout (), чтобы пользовательский интерфейс не блокировался при сжатии.
Август Лиллеас,

возможно, вы могли бы написать свой собственный алгоритм сжатия
Captain kurO

3
@AugustLilleaas теперь вы можете использовать веб-работников, чтобы сделать это :)
Капитан Очевидность

Ответы:


138

Править Похоже, что есть лучшее решение 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("");
}

11
Согласно Википедии, срок действия патентов истек несколько лет назад. Это может быть хорошей идеей, чтобы проверить это, хотя.
Мэтью Крамли

3
LZW слишком стар, чтобы все еще быть запатентованным. Последние патенты закончились в 2003 году или около того. Есть множество бесплатных реализаций.
ypnos

5
Я вижу, по крайней мере, две проблемы с кодом выше: 1) попробуйте сжать «Test, чтобы сжать эти символы, не являющиеся ascii». 2) Об ошибке не сообщается, если код> 65535.
некоторые

5
Здесь представлены реализации на 21 языке. Rosettacode.org/wiki/LZW_compression написано, что он находится в
свободном

5
@ Некоторые я только что выпустил небольшую библиотеку, исправляющую именно те проблемы, на которые вы указываете: pieroxy.net/blog/pages/lz-string/index.html
pieroxy

53

У меня была другая проблема, я не хотел кодировать данные в gzip, но декодировать сжатые данные . Я запускаю код JavaScript за пределами браузера, поэтому мне нужно декодировать его с использованием чистого JavaScript.

Это заняло у меня некоторое время, но я обнаружил, что в библиотеке JSXGraph есть способ чтения сжатых данных.

Вот где я нашел библиотеку: http://jsxgraph.uni-bayreuth.de/wp/2009/09/29/jsxcompressor-zlib-compressed-javascript-code/ Существует даже отдельная утилита, которая может сделать это, JSXCompressor , и код лицензии LGPL.

Просто включите файл jsxcompressor.js в свой проект, и тогда вы сможете прочитать данные в сжатом формате, закодированные в формате 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>

Я понимаю, что это не то, что вы хотели, но я все еще отвечаю здесь, потому что я подозреваю, что это поможет некоторым людям.


3
Большое спасибо за то, что все еще делитесь. Это именно то, что мне было нужно. Вы, вероятно, сэкономили мне часы неудачных поисков, которые я действительно не могу сэкономить. +1
Кирузе

1
Я удивляюсь, почему на земле это называется «компрессор», когда он не компрессор. лол
маттео

1
спустя почти 5 лет все еще полезно. Спасибо. Я помещаю большой JSON прямо на страницу, а не в AJAX. предварительно сжимая его с помощью PHP и распаковывая его обратно на стороне клиента JavaScript - я экономлю некоторые накладные расходы.

Нам нужно <?php..немного? .. Я спрашиваю, потому что это передается в decompressметод.
Jus12

я получаю14:16:28.512 TypeError: e.replace is not a function[Weitere Informationen] jsxcompressor.min.js:19:12201
Bluscream

40

Мы только что выпустили 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'});

7
Пожалуйста, предоставьте пример на стороне клиента для декодирования сжатых строк.
Редсандро

2
var inflate = require('pako/lib/inflate').inflate; var text = inflate(zipped, {to: 'string'});@Redsandro вот как я использую Пако.
Forresto

Этот клиентский пример бросаетincorrect header check
duhaime

17

Я перенес реализацию LZMA из модуля GWT в автономный JavaScript. Это называется LZMA-JS .


1
у вас есть совместимый модуль php для него?
Сирбер

этот URL-адрес 404, и я не могу найти его на github.com/nmrugg либо
hanshenrik

Извините, ссылка изменилась. Вот новый: lzma-js.github.io/LZMA-JS

14

Вот некоторые другие алгоритмы сжатия, реализованные в Javascript:


эта реализация LZMA требует BrowserPlus (расширение браузера) и не выглядит чисто Javascript
Петр Финдейзен

эта реализация LZ77 больше не доступна, и, по крайней мере, ее версия Python (опубликованная на той же странице) была неправильной для довольно простых входных данных.
Петр Финдейзен

geocities мертв, обновит ссылку
Маурисио Шеффер

Это довольно близко к тому, что я хочу. Гугл вещи тоже будут обновлять здесь
Theofanis Pantelides


0

Я предполагаю, что общая реализация сжатия JavaScript на стороне клиента была бы очень дорогой операцией с точки зрения времени обработки, в отличие от времени передачи еще нескольких пакетов HTTP с несжатой полезной нагрузкой.

Вы провели какое-нибудь тестирование, которое дало бы вам представление о том, сколько времени можно сэкономить? Я имею в виду, экономия полосы пропускания не может быть тем, что вы ищете, или не так


Мне нужно сохранить общий размер данных в определенной квоте - размер важнее времени.
Дэвид Цитрон

Хм ... Почему предел? Просто любопытно.
Томалак

Что ж, вот что делает Google: code.google.com/apis/opensocial/articles/… - Типичные квоты Opensocial составляют около 10 тыс.
Дэвид Цитрон

Понятно, спасибо за разъяснения.
Томалак

1
В зависимости от того, насколько интенсивно сжатие, вы можете использовать веб-работников для выполнения задачи за кулисами.
Заклеат

-3

Большинство браузеров могут распаковывать gzip на лету. Это может быть лучшим вариантом, чем реализация javascript.


20
Да, но мне нужно сжать данные на стороне клиента перед их отправкой ...
Дэвид Цитрон,

-4

Вы можете использовать встроенный в страницу Java-апплет 1 пиксель на 1 пиксель и использовать его для сжатия.

Это не JavaScript, и клиентам потребуется среда выполнения Java, но она будет делать то, что вам нужно.


7
Интересно, но я бы предпочел не включать апплет, если это возможно.
Дэвид Цитрон

Я хотел бы добавить реальные случаи использования
CMC

1
Не очень хорошее решение, так как оно добавляет зависимость к Java. Кроме того, не все удосужились установить Java - сайт не будет работать для некоторых людей. Лично у меня установлена ​​Java, так как она мне давно нужна, но я предпочитаю посещать сайты, которые не используют Java.
Онкельборг
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.