Implementasi JavaScript dari Gzip [ditutup]

208

Saya sedang menulis aplikasi Web yang perlu menyimpan data JSON dalam cache sisi-server berukuran kecil melalui AJAX (pikirkan: Kuota sosial ). Saya tidak punya kendali atas server.

Saya perlu mengurangi ukuran data yang disimpan agar tetap berada di dalam kuota sisi server, dan berharap untuk dapat gzip JSON yang dirubah di browser sebelum mengirimnya ke server.

Namun, saya tidak dapat menemukan banyak cara implementasi JavaScript dari Gzip. Adakah saran untuk bagaimana saya dapat mengompres data di sisi klien sebelum mengirimkannya?

David Citron
sumber
6
Anda mengirimnya sampai ke server. Karena itulah ada pengertian "unggah" dan "unduh". Mungkin itu sebabnya Anda mendapatkan jawaban yang memberi tahu Anda "server dapat melakukannya".
Tomalak
3
Implementasi yang tepat dari ini mungkin rumit, karena javascript adalah utas tunggal. Mungkin harus mengompresi dalam batch, menggunakan setTimeout (), sehingga UI tidak mengunci saat mengompresi.
Agustus Lilleaas
mungkin Anda bisa menulis algoritme kompresi Anda sendiri
Kapten kurO
3
@AugustLilleaas sekarang Anda dapat menggunakan webworkers untuk melakukan ini :)
Captain Obvious

Jawaban:

138

Sunting Tampaknya ada solusi LZW yang lebih baik yang menangani string Unicode dengan benar di http://pieroxy.net/blog/pages/lz-string/index.html (Terima kasih kepada pieroxy di komentar).


Saya tidak tahu implementasi gzip, tetapi pustaka jsolait (situsnya sepertinya sudah tidak ada) memiliki fungsi untuk kompresi / dekompresi LZW. Kode ini tercakup dalam 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
sumber
11
Menurut Wikipedia, paten itu berakhir beberapa tahun yang lalu. Mungkin ide yang bagus untuk memeriksanya.
Matthew Crumley
3
LZW terlalu tua untuk dipatenkan. Paten terakhir habis pada tahun 2003 atau lebih. Ada banyak implementasi gratis.
ypnos
5
Saya melihat setidaknya dua masalah dengan kode di atas: 1) mencoba untuk mengompresi "Tes untuk mengompres ini \ u0110 \ u0111 \ u0112 \ u0113 \ u0114 karakter non ascii.", 2) Tidak ada kesalahan yang dilaporkan jika kode> 65535.
beberapa
5
Berikut adalah implementasi dalam 21 bahasa yang berbeda rosettacode.org/wiki/LZW_compression ditulis bahwa itu dalam domain publik dari 2004.
jcubic
5
@Beberapa saya baru saja merilis lib kecil memperbaiki masalah yang Anda tunjukkan di sini: pieroxy.net/blog/pages/lz-string/index.html
pieroxy
53

Saya punya masalah lain, saya tidak ingin menyandikan data di gzip tetapi untuk mendekode data gzip . Saya menjalankan kode javascript di luar browser jadi saya perlu mendekode menggunakan murni javascript .

Butuh beberapa waktu tetapi saya menemukan itu di JSXGraph perpustakaan ada cara untuk membaca data yang di-gzip.

Di sinilah saya menemukan perpustakaan: http://jsxgraph.uni-bayreuth.de/wp/2009/09/29/jsxcompressor-zlib-compressed-javascript-code/ Bahkan ada utilitas mandiri yang dapat melakukan itu, JSXCompressor , dan kodenya dilisensikan LGPL.

Cukup sertakan file jsxcompressor.js dalam proyek Anda dan kemudian Anda akan dapat membaca 64 data gzip yang disandikan:

<!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>

Saya mengerti itu bukan apa yang Anda inginkan tetapi saya masih membalas di sini karena saya kira itu akan membantu beberapa orang.

pcans
sumber
3
Terima kasih banyak untuk masih berbagi. Inilah yang saya butuhkan. Anda mungkin menyelamatkan saya berjam-jam pencarian yang gagal yang saya benar-benar tidak bisa luangkan. +1
Kiruse
1
Saya bertanya-tanya mengapa di bumi ini disebut "kompresor" ketika itu adalah kompresor. lol
matteo
1
hampir 5 tahun kemudian, masih bermanfaat. Terima kasih. Saya membuang JSON besar langsung ke halaman, bukan AJAX'ing itu. dengan pra-mengompresi dengan PHP dan mendekompresnya kembali di sisi klien JavaScript - Saya menyimpan beberapa overhead.
Apakah kita memerlukan <?php..bitnya? .. Saya bertanya karena itu diteruskan ke decompressmetode.
Jus12
saya dapatkan14:16:28.512 TypeError: e.replace is not a function[Weitere Informationen] jsxcompressor.min.js:19:12201
Bluscream
40

Kami baru saja merilis pako https://github.com/nodeca/pako , port zlib ke javascript. Saya pikir itu sekarang implementasi js tercepat dari mengempis / mengembang / gzip / ungzip. Juga, ia memiliki lisensi MIT yang demokratis. Pako mendukung semua opsi zlib dan hasilnya sama dengan biner.

Contoh:

var inflate = require('pako/lib/inflate').inflate; 
var text = inflate(zipped, {to: 'string'});
Vitaly
sumber
7
Berikan contoh sisi klien untuk mendekodekan string yang di-gzip.
Redsandro
2
var inflate = require('pako/lib/inflate').inflate; var text = inflate(zipped, {to: 'string'});@Redandro inilah cara saya menggunakan pako.
forresto
Contoh incorrect header check
sisi klien
17

Saya porting implementasi LZMA dari modul GWT ke JavaScript mandiri. Itu disebut LZMA-JS .


sumber
1
apakah Anda memiliki modul php yang kompatibel untuk itu?
Sirber
url itu adalah 404, dan saya tidak dapat menemukannya di github.com/nmrugg juga
hanshenrik
Maaf, tautannya berubah. Ini yang baru: lzma-js.github.io/LZMA-JS
14

Berikut adalah beberapa algoritma kompresi lain yang diterapkan dalam Javascript:

Mauricio Scheffer
sumber
implementasi LZMA ini membutuhkan BrowserPlus (ekstensi browser) dan tidak terlihat sebagai Javascript murni
Piotr Findeisen
implementasi LZ77 ini tidak lagi tersedia dan setidaknya itu versi Python (diterbitkan pada halaman yang sama) salah untuk input yang cukup sederhana.
Piotr Findeisen
geocities mati, akan memperbarui tautan
Mauricio Scheffer
Ini cukup dekat dengan yang saya inginkan. googling juga akan diperbarui di sini
Theofanis Pantelides
8

Saya tidak menguji, tetapi ada implementasi javascript ZIP, yang disebut JSZip:

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

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

Sirber
sumber
1
Itu zip, bukan gzip, dan menggunakan pako di bawah tenda. Perbedaannya adalah zip memiliki metadata info file.
Vitaly
0

Saya kira implementasi kompresi JavaScript sisi klien generik akan menjadi operasi yang sangat mahal dalam hal waktu pemrosesan dibandingkan dengan waktu transfer beberapa paket HTTP dengan muatan yang tidak terkompresi.

Sudahkah Anda melakukan pengujian yang akan memberi Anda gambaran berapa banyak waktu yang harus dihemat? Maksud saya, penghematan bandwidth tidak bisa seperti yang Anda kejar, atau bisakah?

Tomalak
sumber
Saya perlu menjaga ukuran data total dalam kuota tertentu - ukuran lebih penting daripada waktu.
David Citron
Hm ... Kenapa batasnya? Hanya penasaran.
Tomalak
Nah, inilah Google yang mengambilnya: code.google.com/apis/opensocial/articles/… - kuota Sosial yang umum sekitar 10 ribu.
David Citron
Begitu ya, terima kasih atas klarifikasi.
Tomalak
1
Bergantung pada seberapa intensif kompresi, Anda bisa menggunakan pekerja web untuk melakukan tugas di belakang layar.
zachleat
-3

Sebagian besar browser dapat mendekompresi gzip dengan cepat. Itu mungkin opsi yang lebih baik daripada implementasi javascript.


sumber
20
Ya, tapi saya perlu mengompres data di sisi klien sebelum mengirimnya ...
David Citron
-4

Anda dapat menggunakan applet Java 1 piksel per 1 piksel yang tertanam di halaman dan menggunakannya untuk kompresi.

Ini bukan JavaScript dan klien akan membutuhkan Java runtime tetapi akan melakukan apa yang Anda butuhkan.

Bogdan
sumber
7
Menarik, tapi saya lebih suka menghindari memasukkan applet jika memungkinkan.
David Citron
Saya ingin menambahkan
kasing
1
Bukan solusi yang baik karena menambah ketergantungan ke Jawa. Selain itu, tidak semua orang repot untuk menginstal java - situs tidak akan berfungsi untuk beberapa orang. Secara pribadi saya telah menginstal java sejak saya membutuhkannya untuk waktu yang lama, tapi saya lebih suka mengunjungi situs yang tidak menggunakan java.
Onkelborg