Skip to content

Commit 67f688f

Browse files
committed
refactor: benchmark, optimise code
1 parent 0712944 commit 67f688f

File tree

5 files changed

+207
-19
lines changed

5 files changed

+207
-19
lines changed

README.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# fast-json-stable-stringify
22

3-
deterministic version of `JSON.stringify()` so you can get a consistent hash
4-
from stringified results
3+
Deterministic `JSON.stringify()` - a faster version of @substack's json-stable-strigify without jsonify.
54

65
You can also pass in a custom comparison function.
76

@@ -86,7 +85,7 @@ which outputs:
8685

8786
Pass `true` in `opts.cycles` to stringify circular property as `__cycle__` - the result will not be a valid JSON string in this case.
8887

89-
Without this option TypeError will be thrown.
88+
TypeError will be thrown in case of circular object without this option.
9089

9190

9291
# install
@@ -98,6 +97,23 @@ npm install fast-json-stable-stringify
9897
```
9998

10099

100+
# benchmark
101+
102+
To run benchmark (requires Node.js 6+):
103+
```
104+
node benchmark
105+
```
106+
107+
Results:
108+
```
109+
fast-json-stable-stringify x 17,189 ops/sec ±1.43% (83 runs sampled)
110+
json-stable-stringify x 13,634 ops/sec ±1.39% (85 runs sampled)
111+
fast-stable-stringify x 20,212 ops/sec ±1.20% (84 runs sampled)
112+
faster-stable-stringify x 15,549 ops/sec ±1.12% (84 runs sampled)
113+
The fastest is fast-stable-stringify
114+
```
115+
116+
101117
# license
102118

103-
MIT
119+
[MIT](https://github.com/epoberezkin/fast-json-stable-stringify/blob/master/LICENSE)

benchmark/index.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict';
2+
3+
const Benchmark = require('benchmark');
4+
const suite = new Benchmark.Suite;
5+
const testData = require('./test.json');
6+
7+
8+
const stringifyPackages = {
9+
// 'JSON.stringify': JSON.stringify,
10+
'fast-json-stable-stringify': require('../index'),
11+
'json-stable-stringify': true,
12+
'fast-stable-stringify': true,
13+
'faster-stable-stringify': true
14+
};
15+
16+
17+
for (const name in stringifyPackages) {
18+
let func = stringifyPackages[name];
19+
if (func === true) func = require(name);
20+
21+
suite.add(name, function() {
22+
func(testData);
23+
});
24+
}
25+
26+
suite
27+
.on('cycle', (event) => console.log(String(event.target)))
28+
.on('complete', function () {
29+
console.log('The fastest is ' + this.filter('fastest').map('name'));
30+
})
31+
.run({async: true});

benchmark/test.json

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
[
2+
{
3+
"_id": "59ef4a83ee8364808d761beb",
4+
"index": 0,
5+
"guid": "e50ffae9-7128-4148-9ee5-40c3fc523c5d",
6+
"isActive": false,
7+
"balance": "$2,341.81",
8+
"picture": "http://placehold.it/32x32",
9+
"age": 28,
10+
"eyeColor": "brown",
11+
"name": "Carey Savage",
12+
"gender": "female",
13+
"company": "VERAQ",
14+
"email": "careysavage@veraq.com",
15+
"phone": "+1 (897) 574-3014",
16+
"address": "458 Willow Street, Henrietta, California, 7234",
17+
"about": "Nisi reprehenderit nulla ad officia pariatur non dolore laboris irure cupidatat laborum. Minim eu ex Lorem adipisicing exercitation irure minim sunt est enim mollit incididunt voluptate nulla. Ut mollit anim reprehenderit et aliqua ex esse aliquip. Aute sit duis deserunt do incididunt consequat minim qui dolor commodo deserunt et voluptate.\r\n",
18+
"registered": "2014-05-21T01:56:51 -01:00",
19+
"latitude": 63.89502,
20+
"longitude": 62.369807,
21+
"tags": [
22+
"nostrud",
23+
"nisi",
24+
"consectetur",
25+
"ullamco",
26+
"cupidatat",
27+
"culpa",
28+
"commodo"
29+
],
30+
"friends": [
31+
{
32+
"id": 0,
33+
"name": "Henry Walls"
34+
},
35+
{
36+
"id": 1,
37+
"name": "Janice Baker"
38+
},
39+
{
40+
"id": 2,
41+
"name": "Russell Bush"
42+
}
43+
],
44+
"greeting": "Hello, Carey Savage! You have 4 unread messages.",
45+
"favoriteFruit": "banana"
46+
},
47+
{
48+
"_id": "59ef4a83ff5774a691454e89",
49+
"index": 1,
50+
"guid": "2bee9efc-4095-4c2e-87ef-d08c8054c89d",
51+
"isActive": true,
52+
"balance": "$1,618.15",
53+
"picture": "http://placehold.it/32x32",
54+
"age": 35,
55+
"eyeColor": "blue",
56+
"name": "Elinor Pearson",
57+
"gender": "female",
58+
"company": "FLEXIGEN",
59+
"email": "elinorpearson@flexigen.com",
60+
"phone": "+1 (923) 548-3751",
61+
"address": "600 Bayview Avenue, Draper, Montana, 3088",
62+
"about": "Mollit commodo ea sit Lorem velit. Irure anim esse Lorem sint quis officia ut. Aliqua nisi dolore in aute deserunt mollit ex ea in mollit.\r\n",
63+
"registered": "2017-04-22T07:58:41 -01:00",
64+
"latitude": -87.824919,
65+
"longitude": 69.538927,
66+
"tags": [
67+
"fugiat",
68+
"labore",
69+
"proident",
70+
"quis",
71+
"eiusmod",
72+
"qui",
73+
"est"
74+
],
75+
"friends": [
76+
{
77+
"id": 0,
78+
"name": "Massey Wagner"
79+
},
80+
{
81+
"id": 1,
82+
"name": "Marcella Ferrell"
83+
},
84+
{
85+
"id": 2,
86+
"name": "Evans Mckee"
87+
}
88+
],
89+
"greeting": "Hello, Elinor Pearson! You have 3 unread messages.",
90+
"favoriteFruit": "strawberry"
91+
},
92+
{
93+
"_id": "59ef4a839ec8a4be4430b36b",
94+
"index": 2,
95+
"guid": "ddd6e8c0-95bd-416d-8b46-a768d6363809",
96+
"isActive": false,
97+
"balance": "$2,046.95",
98+
"picture": "http://placehold.it/32x32",
99+
"age": 40,
100+
"eyeColor": "green",
101+
"name": "Irwin Davidson",
102+
"gender": "male",
103+
"company": "DANJA",
104+
"email": "irwindavidson@danja.com",
105+
"phone": "+1 (883) 537-2041",
106+
"address": "439 Cook Street, Chapin, Kentucky, 7398",
107+
"about": "Irure velit non commodo aliqua exercitation ut nostrud minim magna. Dolor ad ad ut irure eu. Non pariatur dolor eiusmod ipsum do et exercitation cillum. Et amet laboris minim eiusmod ullamco magna ea reprehenderit proident sunt.\r\n",
108+
"registered": "2016-09-01T07:49:08 -01:00",
109+
"latitude": -49.803812,
110+
"longitude": 104.93279,
111+
"tags": [
112+
"consequat",
113+
"enim",
114+
"quis",
115+
"magna",
116+
"est",
117+
"culpa",
118+
"tempor"
119+
],
120+
"friends": [
121+
{
122+
"id": 0,
123+
"name": "Ruth Hansen"
124+
},
125+
{
126+
"id": 1,
127+
"name": "Kathrine Austin"
128+
},
129+
{
130+
"id": 2,
131+
"name": "Rivera Munoz"
132+
}
133+
],
134+
"greeting": "Hello, Irwin Davidson! You have 2 unread messages.",
135+
"favoriteFruit": "banana"
136+
}
137+
]

index.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
module.exports = function (obj, opts) {
3+
module.exports = function (data, opts) {
44
if (!opts) opts = {};
55
if (typeof opts === 'function') opts = { cmp: opts };
66
var cycles = (typeof opts.cycles === 'boolean') ? opts.cycles : false;
@@ -21,39 +21,39 @@ module.exports = function (obj, opts) {
2121
node = node.toJSON();
2222
}
2323

24-
if (node === undefined) {
25-
return;
26-
}
27-
if (typeof node !== 'object' || node === null) {
28-
return JSON.stringify(node);
29-
}
24+
if (node === undefined) return;
25+
if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';
26+
if (typeof node !== 'object') return JSON.stringify(node);
27+
3028
var i, out;
3129
if (Array.isArray(node)) {
3230
out = '[';
3331
for (i = 0; i < node.length; i++) {
3432
if (i) out += ',';
35-
out += stringify(node[i]) || JSON.stringify(null);
33+
out += stringify(node[i]) || 'null';
3634
}
3735
return out + ']';
3836
}
3937

38+
if (node === null) return 'null';
39+
4040
if (seen.indexOf(node) !== -1) {
4141
if (cycles) return JSON.stringify('__cycle__');
4242
throw new TypeError('Converting circular structure to JSON');
4343
}
44-
else seen.push(node);
4544

45+
var seenIndex = seen.push(node) - 1;
4646
var keys = Object.keys(node).sort(cmp && cmp(node));
47-
out = '{';
47+
out = '';
4848
for (i = 0; i < keys.length; i++) {
4949
var key = keys[i];
5050
var value = stringify(node[key]);
5151

5252
if (!value) continue;
53-
if (out[1]) out += ',';
53+
if (out) out += ',';
5454
out += JSON.stringify(key) + ':' + value;
5555
}
56-
seen.splice(seen.indexOf(node), 1);
57-
return out + '}';
58-
})(obj);
56+
seen.splice(seenIndex, 1);
57+
return '{' + out + '}';
58+
})(data);
5959
};

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
{
22
"name": "fast-json-stable-stringify",
33
"version": "1.0.2",
4-
"description": "deterministic JSON.stringify() to get deterministic hashes from stringified results",
4+
"description": "deterministic `JSON.stringify()` - a faster version of substack's json-stable-strigify without jsonify",
55
"main": "index.js",
66
"devDependencies": {
7+
"benchmark": "^2.1.4",
78
"coveralls": "^3.0.0",
89
"eslint": "^4.9.0",
10+
"fast-stable-stringify": "latest",
11+
"faster-stable-stringify": "latest",
12+
"json-stable-stringify": "latest",
913
"nyc": "^11.2.1",
1014
"pre-commit": "^1.2.2",
1115
"tape": "~1.0.4"

0 commit comments

Comments
 (0)