Implementação de JavaScript do Gzip [fechado]


208

Estou escrevendo um aplicativo Web que precisa armazenar dados JSON em um cache pequeno e de tamanho fixo do servidor via AJAX (pense em: cotas Opensocial ). Eu não tenho controle sobre o servidor.

Preciso reduzir o tamanho dos dados armazenados para permanecer dentro de uma cota do lado do servidor e esperava poder compactar o JSON com string no navegador antes de enviá-lo ao servidor.

No entanto, não consigo encontrar muita coisa nas implementações de JavaScript do Gzip. Alguma sugestão de como posso compactar os dados no lado do cliente antes de enviá-los?


6
Você está enviando- se ao servidor. É por isso que existem as noções de "upload" e "download". Talvez seja por isso que você esteja recebendo respostas que digam "o servidor pode fazer isso".
Tomalak

3
Uma implementação adequada disso é provavelmente complicada, pois o javascript é de thread único. Provavelmente, seria necessário compactar em lotes, usando setTimeout (), para que a interface do usuário não seja bloqueada durante a compactação.
August Lilleaas 15/09/09

talvez você poderia escrever seu próprio algoritmo de compressão
Capitão Kuro

3
@AugustLilleaas agora você pode usar WebWorkers para fazer isso :)
Capitão Óbvio

Respostas:


138

Editar Parece haver uma solução LZW melhor que lida com seqüências de caracteres Unicode corretamente em http://pieroxy.net/blog/pages/lz-string/index.html (Agradecimentos a pieroxy nos comentários).


Não conheço nenhuma implementação gzip, mas a biblioteca jsolait (o site parece ter desaparecido) tem funções para compactação / descompactação LZW. O código é coberto pela 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
Segundo a Wikipedia, as patentes expiraram alguns anos atrás. Pode ser uma boa ideia verificar isso.
Matthew Crumley

3
O LZW é muito antigo para ser patenteado. As últimas patentes acabaram em 2003 ou mais. Existem muitas implementações gratuitas.
ypnos

5
Vejo pelo menos dois problemas com o código acima: 1) tente compactar "Teste para compactar esses caracteres não ascii.", 2) Nenhum erro será relatado se o código> 65535.
alguns

5
Aqui estão implementações em 21 idiomas diferentes. Rosettacode.org/wiki/LZW_compression está escrito que está em domínio público a partir de 2004.
jcubic

5
@some I acaba de lançar um pequeno lib corrigir exatamente os problemas que você está apontando aqui: pieroxy.net/blog/pages/lz-string/index.html
pieroxy

53

Eu tive outro problema, não queria codificar dados no gzip, mas decodificar dados compactados . Estou executando o código javascript fora do navegador, por isso preciso decodificá-lo usando javascript puro .

Levei algum tempo, mas descobri que na biblioteca JSXGraph existe uma maneira de ler dados compactados em gzip.

Aqui é onde eu encontrei a biblioteca: http://jsxgraph.uni-bayreuth.de/wp/2009/09/29/jsxcompressor-zlib-compressed-javascript-code/ Existe até um utilitário independente que pode fazer isso, JSXCompressor , e o código é licenciado pela LGPL.

Basta incluir o arquivo jsxcompressor.js no seu projeto e, em seguida, você poderá ler os dados compactados em gzip codificados na 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>

Entendo que não era o que você queria, mas ainda respondo aqui porque suspeito que isso ajude algumas pessoas.


3
Muito obrigado por compartilhar ainda. Isso é exatamente o que eu precisava. Você provavelmente me salvou horas de pesquisas malsucedidas que eu realmente não posso poupar. +1
Kiruse

1
Eu me pergunto por que diabos é chamado de "compressor" quando é um descompressor. lol
Matteo

1
quase 5 anos depois, ainda é útil. obrigado. Estou despejando um JSON grande diretamente na página, em vez de fazer o AJAX. pré-compactando-o com PHP e descompactando-o novamente no lado do cliente do JavaScript - estou economizando parte da sobrecarga.

Precisamos do <?php..bit? .. Estou perguntando porque é passado para o decompressmétodo.
precisa saber é

Eu recebo14:16:28.512 TypeError: e.replace is not a function[Weitere Informationen] jsxcompressor.min.js:19:12201
Bluscream

40

Acabamos de lançar o pako https://github.com/nodeca/pako , port of zlib para javascript. Eu acho que agora é a implementação js mais rápida de deflate / inflate / gzip / ungzip. Além disso, possui licença democrática do MIT. Pako suporta todas as opções zlib e seus resultados são binários iguais.

Exemplo:

var inflate = require('pako/lib/inflate').inflate; 
var text = inflate(zipped, {to: 'string'});

7
Forneça um exemplo do lado do cliente para decodificar seqüências de caracteres compactadas com gzip.
Redsandro 26/03

2
var inflate = require('pako/lib/inflate').inflate; var text = inflate(zipped, {to: 'string'});@Redsandro aqui está como eu uso pako.
forresto

Esse exemplo do lado do cliente lançaincorrect header check
duhaime


14

Aqui estão alguns outros algoritmos de compactação implementados em Javascript:


esta implementação LZMA requer BrowserPlus (uma extensão do navegador) e não parece ser puro Javascript
Piotr Findeisen

essa implementação do LZ77 não está mais disponível e pelo menos sua versão do Python (publicada na mesma página) estava incorreta para entradas bastante simples.
Piotr Findeisen

geocities mortas, vai atualizar o link
Mauricio Scheffer

Isso é bem próximo do que eu quero. coisas do Google também serão atualizadas aqui
Theofanis Pantelides


0

Eu acho que uma implementação genérica de compactação JavaScript do lado do cliente seria uma operação muito cara em termos de tempo de processamento, em oposição ao tempo de transferência de mais alguns pacotes HTTP com carga útil não compactada.

Você fez algum teste que lhe desse uma idéia de quanto tempo resta para economizar? Quero dizer, a economia de largura de banda não pode ser o que você procura, ou pode?


Preciso manter o tamanho total dos dados dentro de uma certa cota - o tamanho é mais importante que o tempo.
David Citron

Hm ... Por que o limite? Apenas curioso.
Tomalak

Bem, aqui está a opinião do Google: code.google.com/apis/opensocial/articles/… - As cotas opensociais típicas são de cerca de 10 mil.
David Citron

Entendo, obrigado pelo esclarecimento.
Tomalak

1
Dependendo da intensidade da compactação, você pode usar trabalhadores da Web para executar a tarefa nos bastidores.
zachleat

-3

A maioria dos navegadores pode descomprimir o gzip em tempo real. Essa pode ser uma opção melhor do que uma implementação de javascript.


20
Sim, mas eu preciso para comprimir os dados no lado do cliente antes de enviá-lo para baixo ...
David Citron

-4

Você pode usar um applet Java de 1 pixel por 1 pixel incorporado na página e usá-lo para compactação.

Não é JavaScript e os clientes precisarão de um tempo de execução Java, mas farão o que você precisa.


7
Interessante, mas prefiro evitar a inclusão de um applet, se possível.
David Citron

Gostaria de adicionar os casos de uso reais
cmc

1
Não é uma boa solução, pois adiciona uma dependência ao Java. Além disso, nem todo mundo se preocupou em instalar o java - o site não funcionará para algumas pessoas. Pessoalmente, tenho o java instalado, pois precisava dele há muito tempo, mas prefiro visitar sites que não usam java.
Onkelborg 11/02
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.