Implementación de JavaScript de Gzip [cerrado]

208

Estoy escribiendo una aplicación web que necesita almacenar datos JSON en una pequeña caché del lado del servidor de tamaño fijo a través de AJAX (piense: cuotas operativas ). No tengo control sobre el servidor.

Necesito reducir el tamaño de los datos almacenados para permanecer dentro de una cuota del lado del servidor, y esperaba poder comprimir el JSON en cadena en el navegador antes de enviarlo al servidor.

Sin embargo, no puedo encontrar mucho en el camino de las implementaciones de JavaScript de Gzip. ¿Alguna sugerencia sobre cómo puedo comprimir los datos en el lado del cliente antes de enviarlos?

David Citron
fuente
66
Lo envía hasta al servidor. Es por eso que existen las nociones de "subir" y "descargar". Quizás es por eso que está obteniendo respuestas que le dicen "el servidor puede hacerlo".
Tomalak
3
Una implementación adecuada de esto probablemente sea complicada, ya que JavaScript tiene un solo subproceso. Probablemente tendría que comprimir en lotes, usando setTimeout (), para que la interfaz de usuario no se bloquee durante la compresión.
August Lilleaas
quizás podrías escribir tu propio algoritmo de compresión
Captain kurO
3
@AugustLilleaas ahora puedes usar trabajadores web para hacer esto :)
Capitán Obvio el

Respuestas:

138

Editar Parece haber una mejor solución LZW que maneja cadenas Unicode correctamente en http://pieroxy.net/blog/pages/lz-string/index.html (Gracias a pieroxy en los comentarios).


No conozco ninguna implementación de gzip, pero la biblioteca jsolait (el sitio parece haberse ido) tiene funciones para la compresión / descompresión LZW. El código está cubierto por la 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
fuente
11
Según Wikipedia, las patentes expiraron hace unos años. Sin embargo, podría ser una buena idea comprobar eso.
Matthew Crumley el
3
LZW es demasiado viejo para ser patentado. Las últimas patentes se agotaron en 2003 más o menos. Hay muchas implementaciones gratuitas.
ypnos
55
Veo al menos dos problemas con el código anterior: 1) intentar comprimir "Prueba para comprimir esto \ u0110 \ u0111 \ u0112 \ u0113 \ u0114 caracteres no ascii", 2) No se informa ningún error si el código> 65535.
algunos
55
Aquí hay implementaciones en 21 idiomas diferentes rosettacode.org/wiki/LZW_compression está escrito que está en dominio público desde 2004.
jcubic
55
@algunos acabo de lanzar una pequeña biblioteca que corrige exactamente los problemas que estás señalando aquí: pieroxy.net/blog/pages/lz-string/index.html
pieroxy
53

Tuve otro problema, no quería codificar datos en gzip sino decodificar datos comprimidos . Estoy ejecutando código JavaScript fuera del navegador, así que necesito decodificarlo usando puro javascript .

Me tomó algo de tiempo pero lo encontré en el JSXGraph biblioteca hay una manera de leer datos comprimidos.

Aquí es donde encontré la biblioteca: http://jsxgraph.uni-bayreuth.de/wp/2009/09/29/jsxcompressor-zlib-compressed-javascript-code/ Incluso hay una utilidad independiente que puede hacer eso, JSXCompressor , y el código está licenciado por LGPL.

Simplemente incluya el archivo jsxcompressor.js en su proyecto y luego podrá leer los datos comprimidos codificados en 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>

Entiendo que no es lo que querías, pero todavía respondo aquí porque sospecho que ayudará a algunas personas.

pcans
fuente
3
Muchas gracias por seguir compartiendo. Esto es exactamente lo que necesitaba. Probablemente me ahorraste horas de búsqueda infructuosa que realmente no puedo escatimar. +1
Kiruse
1
Me pregunto por qué demonios se llama "compresor" cuando es un compresor de la ONU. lol
matteo
1
Casi 5 años después, sigue siendo útil. gracias. Estoy volcando un JSON grande directamente a la página, en lugar de AJAX. precomprimiéndolo con PHP y descomprimiéndolo nuevamente en el lado del cliente de JavaScript, estoy ahorrando parte de la sobrecarga.
¿Necesitamos el <?php..bit? .. Pregunto porque se pasa al decompressmétodo.
Jus12
consigo14:16:28.512 TypeError: e.replace is not a function[Weitere Informationen] jsxcompressor.min.js:19:12201
Bluscream
40

Acabamos de lanzar pako https://github.com/nodeca/pako , puerto de zlib a javascript. Creo que ahora es la implementación js más rápida de deflate / inflate / gzip / ungzip. Además, tiene licencia MIT democrática. Pako admite todas las opciones de zlib y sus resultados son binarios iguales.

Ejemplo:

var inflate = require('pako/lib/inflate').inflate; 
var text = inflate(zipped, {to: 'string'});
Vitalia
fuente
77
Proporcione un ejemplo del lado del cliente para decodificar cadenas comprimidas.
Redsandro
2
var inflate = require('pako/lib/inflate').inflate; var text = inflate(zipped, {to: 'string'});@Redsandro así es como uso pako.
forresto
Ese ejemplo del lado del cliente arrojaincorrect header check
duhaime
17

Porté una implementación de LZMA desde un módulo GWT a JavaScript independiente. Se llama LZMA-JS .


fuente
1
¿tienes un módulo php compatible para ello?
Sirber
que url es de 404, y no puedo encontrar en github.com/nmrugg bien
hanshenrik
Lo sentimos, el enlace ha cambiado. Aquí está el nuevo: lzma-js.github.io/LZMA-JS
14

Aquí hay algunos otros algoritmos de compresión implementados en Javascript:

Mauricio Scheffer
fuente
esta implementación de LZMA requiere BrowserPlus (una extensión de navegador) y no parece ser Javascript puro
Piotr Findeisen
esta implementación LZ77 ya no está disponible y al menos su versión de Python (publicada en la misma página) era incorrecta para entradas bastante simples.
Piotr Findeisen
geocities dead, actualizará el enlace
Mauricio Scheffer
Esto está bastante cerca de lo que quiero. las cosas de Google también se actualizarán aquí
Theofanis Pantelides
0

Supongo que una implementación de compresión de JavaScript genérica del lado del cliente sería una operación muy costosa en términos de tiempo de procesamiento en lugar del tiempo de transferencia de unos pocos paquetes HTTP más con carga útil sin comprimir.

¿Has hecho alguna prueba que te dé una idea de cuánto tiempo hay para ahorrar? Quiero decir, el ahorro de ancho de banda no puede ser lo que buscas, ¿o sí?

Tomalak
fuente
Necesito mantener el tamaño total de los datos dentro de una cuota determinada: el tamaño es más importante que el tiempo.
David Citron
Hm ... ¿Por qué es el límite? Sólo curioso.
Tomalak el
Bueno, aquí está la opinión de Google: code.google.com/apis/opensocial/articles/… - Las cuotas típicas de Opensocial son alrededor de 10K.
David Citron el
Ya veo, gracias por la aclaración.
Tomalak
1
Dependiendo de qué tan intensiva sea la compresión, puede usar trabajadores web para realizar la tarea detrás de escena.
zachleat
-3

La mayoría de los navegadores pueden descomprimir gzip sobre la marcha. Esa podría ser una mejor opción que una implementación de JavaScript.


fuente
20
Sí, pero necesito comprimir los datos en el lado del cliente antes de enviarlos ...
David Citron
-4

Puede usar un applet Java de 1 píxel por 1 píxel incrustado en la página y usarlo para la compresión.

No es JavaScript y los clientes necesitarán un tiempo de ejecución de Java, pero hará lo que usted necesite.

Bogdan
fuente
77
Interesante, pero prefiero evitar incluir un applet si es posible.
David Citron
Me gustaría agregar los casos de uso real
cmc
1
No es una buena solución ya que agrega una dependencia a Java. Aparte de eso, no todos se han molestado en instalar Java: el sitio no funcionará para algunas personas. Personalmente, tengo Java instalado ya que lo necesitaba para algo hace mucho tiempo, pero prefiero visitar sitios que no usan Java.
Onkelborg