Implementacja JavaScript Gzip [zamknięta]

208

Piszę aplikację sieci Web, która musi przechowywać dane JSON w niewielkiej pamięci podręcznej po stronie serwera o stałej wielkości za pośrednictwem AJAX (pomyśl: limity Openocial ). Nie mam kontroli nad serwerem.

Muszę zmniejszyć rozmiar przechowywanych danych, aby pozostać w ramach limitu po stronie serwera, i miałem nadzieję, że będę w stanie zgzipować JSON w przeglądarce przed wysłaniem go na serwer.

Jednak nie mogę znaleźć wiele na drodze do implementacji JavaScript w Gzip. Wszelkie sugestie dotyczące sposobu kompresji danych po stronie klienta przed wysłaniem?

David Citron
źródło
6
Wysyłasz go do serwera. Właśnie dlatego istnieją pojęcia „wysyłanie” i „pobieranie”. Być może dlatego otrzymujesz odpowiedzi, które mówią ci „serwer może to zrobić”.
Tomalak
3
Prawidłowa implementacja tego jest prawdopodobnie trudna, ponieważ javascript jest jednowątkowy. Prawdopodobnie musiałby się kompresować partiami, używając setTimeout (), aby interfejs użytkownika nie blokował się podczas kompresji.
August Lilleaas,
być może mógłbyś napisać swój własny algorytm kompresji
Captain kurO
3
@AugustLilleaas, teraz możesz to zrobić za pomocą webmasterów :)
Captain Obvious

Odpowiedzi:

138

Edycja Wydaje się, że istnieje lepsze rozwiązanie LZW, które poprawnie obsługuje ciągi Unicode pod adresem http://pieroxy.net/blog/pages/lz-string/index.html (Dzięki pieroxy w komentarzach).


Nie znam żadnych implementacji gzip, ale biblioteka jsolait (strona wydaje się zniknąć) ma funkcje kompresji / dekompresji LZW. Kod jest objęty licencją 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("");
}
Matthew Crumley
źródło
11
Według Wikipedii patenty wygasły kilka lat temu. Warto jednak to sprawdzić.
Matthew Crumley
3
LZW jest o wiele za stary, aby móc go opatentować. Ostatnie patenty wygasły w 2003 roku. Istnieje mnóstwo bezpłatnych wdrożeń.
ypnos
5
Widzę co najmniej dwa problemy z powyższym kodem: 1) spróbuj skompresować „Test, aby skompresować to \ u0110 \ u0111 \ u0112 \ u0113 \ u0114 nie ascii.”, 2) Nie jest zgłaszany błąd, jeśli kod> 65535.
niektóre
5
Oto implementacje w 21 różnych językach rosettacode.org/wiki/LZW_compression napisano, że jest to domena publiczna od 2004 roku.
jcubic
5
@some Właśnie wydałem małą bibliotekę, która dokładnie koryguje problemy, które tutaj wskazujesz: pieroxy.net/blog/pages/lz-string/index.html
pieroxy
53

Miałem inny problem, nie chciałem kodować danych w gzipie, ale dekodować dane w gzipie . Używam kodu javascript poza przeglądarką, więc muszę go zdekodować przy użyciu czystego javascript.

Zajęło mi to trochę czasu, ale odkryłem, że w bibliotece JSXGraph istnieje sposób na odczyt danych spakowanych gzipem.

Oto gdzie znalazłem bibliotekę: http://jsxgraph.uni-bayreuth.de/wp/2009/09/29/jsxcompressor-zlib-compressed-javascript-code/ Istnieje nawet samodzielne narzędzie, które może to zrobić, JSXCompressor , a kod jest na licencji LGPL.

Po prostu dołącz plik jsxcompressor.js do swojego projektu, a wtedy będziesz mógł odczytać dane gzipowane w formacie 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>

Rozumiem, że nie tego chciałeś, ale wciąż odpowiadam tutaj, ponieważ podejrzewam, że pomoże to niektórym ludziom.

pcans
źródło
3
Bardzo dziękuję za dzielenie się. Właśnie tego potrzebowałem. Prawdopodobnie oszczędziłeś mi godzin nieudanych poszukiwań, których tak naprawdę nie mogę poświęcić. +1
Kiruse,
1
Zastanawiam się, dlaczego na ziemi nazywa się ją „kompresorem”, skoro jest sprężarką UN. lol
matteo
1
prawie 5 lat później nadal jest przydatny. Dziękuję Ci. Zrzucam duży JSON bezpośrednio na stronę, zamiast go AJAX. wstępnie kompresując go za pomocą PHP i dekompresując go z powrotem po stronie klienta JavaScript - oszczędzam część kosztów ogólnych.
Czy potrzebujemy <?php..bitu? .. Pytam, ponieważ jest przekazywany do decompressmetody.
Jus12
dostaję14:16:28.512 TypeError: e.replace is not a function[Weitere Informationen] jsxcompressor.min.js:19:12201
Bluscream
40

Właśnie wydaliśmy pakiet pako https://github.com/nodeca/pako , port zlib na javascript. Myślę, że jest to teraz najszybsza implementacja js deflate / inflate / gzip / ungzip. Ma także demokratyczną licencję MIT. Pako obsługuje wszystkie opcje zlib, a jego wyniki są równe binarnie.

Przykład:

var inflate = require('pako/lib/inflate').inflate; 
var text = inflate(zipped, {to: 'string'});
Witalij
źródło
7
Podaj przykład po stronie klienta do dekodowania napisów gzip.
Redsandro
2
var inflate = require('pako/lib/inflate').inflate; var text = inflate(zipped, {to: 'string'});@ Redsandro oto jak używam Pako.
forresto
Ten przykład dla klientów rzucaincorrect header check
duhaime
17

Implementowałem LZMA z modułu GWT do samodzielnego JavaScript. To się nazywa LZMA-JS .


źródło
1
czy masz do tego kompatybilny moduł php?
Sirber,
że adres URL jest 404, a ja nie mogę go znaleźć na github.com/nmrugg albo
hanshenrik
Przepraszamy, link został zmieniony. Oto nowy: lzma-js.github.io/LZMA-JS
14

Oto kilka innych algorytmów kompresji zaimplementowanych w JavaScript:

Mauricio Scheffer
źródło
ta implementacja LZMA wymaga BrowserPlus (rozszerzenie przeglądarki) i nie wygląda na czysty Javascript
Piotr Findeisen
ta implementacja LZ77 nie jest już dostępna i przynajmniej jej wersja w języku Python (opublikowana na tej samej stronie) była niepoprawna dla dość prostych danych wejściowych.
Piotr Findeisen,
Geocities dead, zaktualizuje link
Mauricio Scheffer
To bardzo blisko tego, czego chcę. zaktualizowane zostaną też rzeczy
googlujące
8

Nie testowałem, ale istnieje implementacja ZIP w javascript, o nazwie JSZip:

http://jszip.stuartk.co.uk/

https://stuk.github.io/jszip/

Sirber
źródło
1
To jest zip, a nie gzip, i używa pako pod maską. Różnica polega na tym, że zip ma metadane informacji o pliku.
Witalij,
0

Wydaje mi się, że ogólna implementacja kompresji JavaScript po stronie klienta byłaby bardzo kosztowną operacją pod względem czasu przetwarzania, w przeciwieństwie do czasu przesyłania kilku kolejnych pakietów HTTP z nieskompresowanym ładunkiem.

Czy wykonałeś jakieś testy, które dałyby Ci wyobrażenie, ile czasu jest do zaoszczędzenia? To znaczy, oszczędności pasma nie mogą być tym, czego szukasz, czy może?

Tomalak
źródło
Muszę utrzymać całkowity rozmiar danych w ramach określonego przydziału - rozmiar jest ważniejszy niż czas.
David Citron,
Hm ... Dlaczego jest limit? Po prostu ciekawy.
Tomalak,
Cóż, oto opinia Google: code.google.com/apis/opensocial/articles/… - Typowe limity Openocial wynoszą około 10 000.
David Citron,
Rozumiem, dziękuję za wyjaśnienie.
Tomalak
1
W zależności od intensywności kompresji można użyć robotów WWW do wykonania zadania za kulisami.
zachleat
-3

Większość przeglądarek może dekompresować gzip w locie. To może być lepsza opcja niż implementacja javascript.


źródło
20
Tak, ale muszę skompresować dane po stronie klienta przed wysłaniem ich w dół ...
David Citron
-4

Możesz użyć apletu Java 1 piksel na 1 piksel osadzonego na stronie i użyć go do kompresji.

To nie jest JavaScript, a klienci będą potrzebować środowiska wykonawczego Java, ale zrobi to, czego potrzebujesz.

Bogdan
źródło
7
Ciekawe, ale wolałbym unikać dołączania apletu, jeśli to możliwe.
David Citron,
Chciałbym dodać prawdziwe przypadki użycia
cmc
1
Nie jest to dobre rozwiązanie, ponieważ dodaje zależność do Javy. Poza tym nie wszyscy starali się zainstalować Javę - strona nie będzie działać dla niektórych osób. Osobiście mam zainstalowaną Javę, ponieważ już dawno jej potrzebowałem, ale wolę odwiedzać witryny, które nie używają javy.
Onkelborg