JSON compression (v2)

Revision 2 of this benchmark created by Kim T on


Description

Checking different JSON compression libs and techniques

Preparation HTML

<script src="https://playground.bynduk.com/compress-new/msgpack.min.js">
</script>
<script src="https://playground.bynduk.com/compress-new/lzma.min.js"></script>
<script src="https://playground.bynduk.com/compress-new/lzma_worker.min.js"></script>
<script src="https://playground.bynduk.com/compress-new/jsonh.min.js"></script>
<script src="https://playground.bynduk.com/compress-new/bison.min.js"></script>
<script src="https://playground.bynduk.com/compress-new/lzw-async.min.js"></script>

Setup

var json = [{
      surname: 'Jones',
      age: 15,
      gender: 'Male',
      id: 1
    }, {
      age: 15,
      gender: 'Female',
      id: 2,
      surname: 'Adams'
    }, {
      age: 34,
      gender: 'Female',
      id: 3,
      firstname: 'Sally'
    }, {
      age: 22,
      gender: 'Male',
      location: 'London'
    }, {
      surname: 'Turley',
      age: 19,
      gender: 'Male',
      id: 8
    }, {
      age: 76,
      gender: 'Female',
      id: 2,
      surname: 'Tempest'
    }, {
      age: 34,
      gender: 'Female',
      id: 3,
      firstname: 'Sally'
    }, {
      age: 22,
      gender: 'Male',
      location: 'London'
    }];
    
    if (!window.abc) { window.abc = {}; }
    
    // create a new object and turn data into set of keys and their references
    
    
    function pack(items) {
      var data = {
        k: [],
        d: []
      };
      data.d = process(items, data.k, set);
      return data;
    }
    
    // grab the references and return the key values
    
    
    function unpack(items) {
      return process(items.d, items.k, get);
    }
    
    // loop through a list and run a function on its keys and values
    
    
    function process(items, keys, func) {
      var list = [],
          obj = {};
      for (var i = 0; i < items.length; ++i) {
        obj = {};
        for (var item in items[i]) {
          obj[func(item, keys)] = func(items[i][item], keys);
        }
        list.push(obj);
      }
      return list;
    }
    
    // set a key and return its index
    
    
    function set(item, items) {
      for (var i = 0; i < items.length; ++i) {
        if (item == items[i]) {
          return i;
        }
      }
      items.push(item);
      return items.length - 1;
    }
    
    // get a key value by its index
    
    
    function get(item, items) {
      return items[parseInt(item, 10)];
    }
    
    
    //LZW Compression/Decompression for Strings
    var LZW = {
        compress: function (uncompressed) {
            "use strict";
            // Build the dictionary.
            var i,
                dictionary = {},
                c,
                wc,
                w = "",
                result = [],
                dictSize = 256;
            for (i = 0; i < 256; i += 1) {
                dictionary[String.fromCharCode(i)] = i;
            }
     
            for (i = 0; i < uncompressed.length; i += 1) {
                c = uncompressed.charAt(i);
                wc = w + c;
                //Do not use dictionary[wc] because javascript arrays 
                //will return values for array['pop'], array['push'] etc
               // if (dictionary[wc]) {
                if (dictionary.hasOwnProperty(wc)) {
                    w = wc;
                } else {
                    result.push(dictionary[w]);
                    // Add wc to the dictionary.
                    dictionary[wc] = dictSize++;
                    w = String(c);
                }
            }
     
            // Output the code for w.
            if (w !== "") {
                result.push(dictionary[w]);
            }
            return result;
        },
     
     
        decompress: function (compressed) {
            "use strict";
            // Build the dictionary.
            var i,
                dictionary = [],
                w,
                result,
                k,
                entry = "",
                dictSize = 256;
            for (i = 0; i < 256; i += 1) {
                dictionary[i] = String.fromCharCode(i);
            }
     
            w = String.fromCharCode(compressed[0]);
            result = w;
            for (i = 1; i < compressed.length; i += 1) {
                k = compressed[i];
                if (dictionary[k]) {
                    entry = dictionary[k];
                } else {
                    if (k === dictSize) {
                        entry = w + w.charAt(0);
                    } else {
                        return null;
                    }
                }
     
                result += entry;
     
                // Add w+entry[0] to the dictionary.
                dictionary[dictSize++] = w + entry.charAt(0);
     
                w = entry;
            }
            return result;
        }
    };

Teardown


    window.abc[testname] = data;
  

Test runner

Ready to run.

Testing in
TestOps/sec
Kim's Method (1KB)
var testname = 'kim';
var data = pack(json);
ready
msgpack.js (7KB)
var testname = 'msgpack';
var data = msgpack.pack(json);
ready
LZMA.compress (51KB)
var testname = 'LZMA';
var data = LZMA.compress(JSON.stringify(json), 1);
ready
hpack.js (1KB)
var testname = 'hpack';
var data = JSONH.stringify(json);
ready
bison.js (2KB)
var testname = 'bison';
var data = BISON.encode(json)
ready
LZWAsync.compress (4KB)
var testname = 'LZWAsync';
var data = 'not complete';
LZWAsync.compress({
        input: JSON.stringify(json),
        output : function(output) { data = output; }
});
ready
LZW.compress (1KB)
var testname = 'LZW';
var data = LZW.compress(JSON.stringify(json));
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.