Implémentation JavaScript de Gzip [fermé]

208

J'écris une application Web qui a besoin de stocker des données JSON dans un petit cache côté serveur de taille fixe via AJAX (pensez: quotas sociaux ouvrés ). Je n'ai aucun contrôle sur le serveur.

Je dois réduire la taille des données stockées pour rester dans un quota côté serveur, et j'espérais pouvoir compresser le JSON stratifié dans le navigateur avant de l'envoyer au serveur.

Cependant, je ne trouve pas grand-chose dans la manière des implémentations JavaScript de Gzip. Avez-vous des suggestions sur la façon de compresser les données côté client avant de les envoyer?

David Citron
la source
6
Vous l' envoyez jusqu'à au serveur. C'est pourquoi il y a les notions de "upload" et "download". C'est peut-être pour cela que vous obtenez des réponses qui vous disent "le serveur peut le faire".
Tomalak
3
Une implémentation correcte de ceci est probablement délicate, car javascript est un thread unique. Il devrait probablement être compressé par lots, à l'aide de setTimeout (), afin que l'interface utilisateur ne se verrouille pas lors de la compression.
August Lilleaas,
vous pourriez peut-être écrire votre propre algorithme de compression
Captain kurO
3
@AugustLilleaas vous pouvez maintenant utiliser des webworkers pour ce faire :)
Captain Obvious

Réponses:

138

Modifier Il semble y avoir une meilleure solution LZW qui gère correctement les chaînes Unicode sur http://pieroxy.net/blog/pages/lz-string/index.html (Merci à pieroxy dans les commentaires).


Je ne connais aucune implémentation de gzip, mais la bibliothèque jsolait (le site semble avoir disparu) a des fonctions pour la compression / décompression LZW. Le code est couvert par 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
la source
11
Selon Wikipedia, les brevets ont expiré il y a quelques années. Ce pourrait être une bonne idée de vérifier cela.
Matthew Crumley
3
LZW est beaucoup trop vieux pour être encore breveté. Les derniers brevets ont expiré en 2003 environ. Il existe de nombreuses implémentations gratuites.
ypnos
5
Je vois au moins deux problèmes avec le code ci-dessus: 1) essayez de compresser "Test pour compresser ces caractères non ascii \ u0110 \ u0111 \ u0112 \ u0113 \ u0114.", 2) Aucune erreur n'est signalée si le code> 65535.
certains
5
Voici les implémentations dans 21 langues différentes rosettacode.org/wiki/LZW_compression il est écrit que c'est dans le domaine public à partir de 2004.
jcubic
5
@some Je viens de publier une petite bibliothèque corrigeant exactement les problèmes que vous signalez
pieroxy
53

J'ai eu un autre problème, je ne voulais pas encoder des données en gzip mais décoder des données gzippées . J'utilise du code javascript en dehors du navigateur, je dois donc le décoder en utilisant du javascript pur .

Cela m'a pris du temps mais j'ai trouvé que dans le JSXGraph bibliothèque il y avait un moyen de lire des données compressées.

Voici où j'ai trouvé la bibliothèque: http://jsxgraph.uni-bayreuth.de/wp/2009/09/29/jsxcompressor-zlib-compressed-javascript-code/ Il existe même un utilitaire autonome qui peut le faire, JSXCompressor et le code est sous licence LGPL.

Incluez simplement le fichier jsxcompressor.js dans votre projet et vous pourrez alors lire des données gzippées encodées 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>

Je comprends que ce n'est pas ce que vous vouliez mais je réponds toujours ici parce que je soupçonne que cela aidera certaines personnes.

PCans
la source
3
Merci beaucoup pour toujours partager. C'est exactement ce dont j'avais besoin. Vous m'avez probablement sauvé des heures de recherches infructueuses que je ne peux vraiment pas épargner. +1
Kiruse
1
Je me demande pourquoi diable on l'appelle "compresseur" quand c'est un UNcompressor. lol
matteo
1
près de 5 ans plus tard, toujours utile. Merci. Je vide un grand JSON directement sur la page, au lieu de l'ajaxer. en le pré-compressant avec PHP et en le décompressant dans le côté client de JavaScript - j'économise une partie de la surcharge.
Avons-nous besoin du <?php..bit? .. Je demande parce qu'il est passé à la decompressméthode.
Jus12
je reçois14:16:28.512 TypeError: e.replace is not a function[Weitere Informationen] jsxcompressor.min.js:19:12201
Bluscream
40

Nous venons de publier pako https://github.com/nodeca/pako , port de zlib vers javascript. Je pense que c'est maintenant l'implémentation js la plus rapide de deflate / inflate / gzip / ungzip. En outre, il dispose d'une licence MIT démocratique. Pako prend en charge toutes les options zlib et ses résultats sont binaires égaux.

Exemple:

var inflate = require('pako/lib/inflate').inflate; 
var text = inflate(zipped, {to: 'string'});
Vitaly
la source
7
Veuillez fournir un exemple côté client pour le décodage de chaînes gzippées.
Redsandro
2
var inflate = require('pako/lib/inflate').inflate; var text = inflate(zipped, {to: 'string'});@Redsandro voici comment j'utilise pako.
forresto
Cet exemple côté client jetteincorrect header check
duhaime
17

J'ai porté une implémentation de LZMA à partir d'un module GWT en JavaScript autonome. Cela s'appelle LZMA-JS .


la source
1
avez-vous un module php compatible pour cela?
Sirber
cette URL est 404, et je ne peux pas trouver sur github.com/nmrugg soit
hanshenrik
Désolé, le lien a été modifié. Voici le nouveau: lzma-js.github.io/LZMA-JS
14

Voici quelques autres algorithmes de compression implémentés en Javascript:

Mauricio Scheffer
la source
cette implémentation LZMA nécessite BrowserPlus (une extension de navigateur) et ne semble pas être du pur Javascript
Piotr Findeisen
cette implémentation LZ77 n'est plus disponible et au moins sa version Python (publiée sur la même page) était incorrecte pour des entrées assez simples.
Piotr Findeisen
géocités mortes, mettra à jour le lien
Mauricio Scheffer
C'est assez proche de ce que je veux. googler les choses aussi sera mis à jour ici
Theofanis Pantelides
8

Je n'ai pas testé, mais il existe une implémentation javascript de ZIP, appelée JSZip:

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

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

Sirber
la source
1
C'est zip, pas gzip, et il utilise pako sous le capot. La différence est que zip contient des métadonnées d'informations sur les fichiers.
Vitaly
0

Je suppose qu'une implémentation générique de compression JavaScript côté client serait une opération très coûteuse en termes de temps de traitement, par opposition au temps de transfert de quelques paquets HTTP supplémentaires avec une charge utile non compressée.

Avez-vous fait des tests qui vous donneraient une idée du temps qu'il vous reste à gagner? Je veux dire, les économies de bande passante ne peuvent pas être ce que vous recherchez, n'est-ce pas?

Tomalak
la source
J'ai besoin de garder la taille totale des données dans un certain quota - la taille est plus importante que le temps.
David Citron
Hm ... Pourquoi est la limite? Juste curieux.
Tomalak
Eh bien, voici la position de Google à ce sujet: code.google.com/apis/opensocial/articles/… - Les quotas OpenSocial typiques sont d'environ 10 000.
David Citron
Je vois, merci pour la clarification.
Tomalak
1
Selon l'intensité de la compression, vous pouvez utiliser des travailleurs Web pour effectuer la tâche en arrière-plan.
zachleat
-3

La plupart des navigateurs peuvent décompresser gzip à la volée. Cela pourrait être une meilleure option qu'une implémentation javascript.


la source
20
Oui, mais j'ai besoin de compresser les données côté client avant de les envoyer ...
David Citron
-4

Vous pouvez utiliser une applet Java 1 pixel par 1 pixel intégrée à la page et l'utiliser pour la compression.

Ce n'est pas du JavaScript et les clients auront besoin d'un runtime Java mais il fera ce dont vous avez besoin.

Bogdan
la source
7
Intéressant, mais je préfère éviter d'inclure une applet si possible.
David Citron
Je voudrais ajouter les cas d'utilisation réels
cmc
1
Pas une bonne solution car elle ajoute une dépendance à Java. En dehors de cela, tout le monde n'a pas pris la peine d'installer Java - le site ne fonctionnera pas pour certaines personnes. Personnellement, j'ai installé Java depuis que j'en avais besoin il y a longtemps, mais je préfère visiter des sites qui n'utilisent pas Java.
Onkelborg le