/data-formats-benchmark-node-typescript

benchmark of serialize/deserialize operations for data formats like JSON, BSON, MessagePack, etc.

Primary LanguageJavaScriptThe UnlicenseUnlicense

data-formats-benchmark-node-typescript

benchmark of serialize/deserialize operations for data formats like JSON, BSON, MessagePack, etc.

BSON: https://github.com/mongodb/js-bson

MessagePack: https://github.com/msgpack/msgpack-javascript

Google Protocol Buffers: https://www.npmjs.com/package/google-protobuf

Protocol Buffers for JS/TS: https://github.com/protobufjs/protobuf.js

Also, check: https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats

install

npm i

build

npm run build

benchmarks

we can run many encode/decode operations for inputs like:

const rawMsg = {
  a: [ 1, '2', true, 2021-06-19T15:24:01.012Z ],
  b: true,
  c: 123456789,
  d: 2021-06-19T15:24:01.012Z,
  e: 2.718281828459045,
  f: 123.456789,
  pi: 3.141592653589793,
  r: 0.960430998670188,
  s: 'string',
  t: 'Lorem ipsum ...'
}

Proto file for this:

syntax = "proto3";

package benchmark;

import "google/protobuf/timestamp.proto";
import "google/protobuf/any.proto";

message InputMessage {
  repeated google.protobuf.Any a = 1;
  bool b = 2;
  int32 c = 3;
  google.protobuf.Timestamp d = 4;
  double e = 5;
  float f = 6;
  double pi = 7;
  float r = 8;
  string s = 9;
  string t = 10;
}

I find the Java-like code, which was generated by Google Protobuf lib, and its usage very ugly; I cannot use raw/generic JS objects.

const benchmark = require('./benchmark_pb'); // load once
const msg = new benchmark.InputMessage();
// a: any[]
msg.setAList([]);
msg.addA(new any_pb.Any(1));
msg.addA(new any_pb.Any('2'));
msg.addA(new any_pb.Any(true));
msg.addA(new any_pb.Any(new timestamp_pb.Timestamp()));

msg.setB(true);
msg.setC(123456);
msg.setD(new timestamp_pb.Timestamp());
msg.setE(Math.E);
msg.setF(123.456789);
msg.setPi(Math.PI);
msg.setR(Math.random());
msg.setS('string');
msg.setT('Lorem ipsum ...');

ProtobufJs seems nicer than above:

const root = pbjs.loadSync(resolve(__dirname, '..', 'benchmark.proto')); // load once
const InputMessage = root.lookupType('benchmark.InputMessage'); // load once
const msg = InputMessage.create(rawObj);

TS-Node

  • ts-node 10.0.0
  • typescript 4.3.4
npm run bench:ts

result for 1000 operations

format           time (ms)  serialized (KB)
json                   17     671.2
bson                   77     603.5
msgpack                69     570.3
google-protobuf       120     530.3
protobufjs             43     528.3

result for 1000000 operations

format           time (s)   serialized (MB)
json                9.17     655.4
bson               20.14     589.4
msgpack            14.06     556.9
google-protobuf    21.17     517.8
protobufjs          4.12     515.9

Node

Node 14.17.0

npm run bench:js

result for 1000 operations

format        time (ms)   serialized (KB)
json                 14     671.2
bson                 80     603.5
msgpack              65     570.3
google-protobuf     112     530.3
protobufjs           45     528.3

result for 1000000 operations

format            time (s)  serialized (MB)
json                 9.825    655.4
bson                18.905    589.4
msgpack             13.917    556.9
google-protobuf     21.128    517.8
protobufjs           4.391    515.9

conclusion

If you are using Node (JavaScript/TypeScript), native JSON module is still doing a good job!

You will get different results if you use different programming languages and libraries.