Skip to content

Commit aa22300

Browse files
BridgeARJonasBa
authored andcommitted
assert,util: improve deep object comparison performance
This improves the performance for almost all objects when comparing them deeply. PR-URL: nodejs#57648 Reviewed-By: Jordan Harband <[email protected]> Reviewed-By: Bryan English <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
1 parent 69ea1b1 commit aa22300

File tree

6 files changed

+336
-167
lines changed

6 files changed

+336
-167
lines changed

benchmark/assert/deepequal-map.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function benchmark(method, n, values, values2) {
3131
}
3232

3333
function main({ n, len, method, strict }) {
34-
const array = Array(len).fill(1);
34+
const array = Array.from({ length: len }, () => '');
3535

3636
switch (method) {
3737
case 'deepEqual_primitiveOnly': {

benchmark/assert/deepequal-prims-and-objs-big-loop.js

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ const primValues = {
1414
'number': 1_000,
1515
'boolean': true,
1616
'object': { property: 'abcdef' },
17-
'object_other_property': { property: 'abcdef' },
1817
'array': [1, 2, 3],
1918
'set_object': new Set([[1]]),
2019
'set_simple': new Set([1, 2, 3]),

benchmark/assert/deepequal-set.js

+30-11
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ const { deepEqual, deepStrictEqual, notDeepEqual, notDeepStrictEqual } =
66

77
const bench = common.createBenchmark(main, {
88
n: [1e3],
9-
len: [5e2],
9+
len: [2, 1e2],
1010
strict: [0, 1],
11+
order: ['insert', 'random', 'reversed'],
1112
method: [
1213
'deepEqual_primitiveOnly',
1314
'deepEqual_objectOnly',
@@ -16,12 +17,30 @@ const bench = common.createBenchmark(main, {
1617
'notDeepEqual_objectOnly',
1718
'notDeepEqual_mixed',
1819
],
20+
}, {
21+
combinationFilter(p) {
22+
return p.order !== 'random' || p.strict === 1 && p.method !== 'notDeepEqual_objectOnly';
23+
},
1924
});
2025

21-
function benchmark(method, n, values, values2) {
26+
function shuffleArray(array) {
27+
for (let i = array.length - 1; i > 0; i--) {
28+
const j = Math.floor(Math.random() * (i + 1));
29+
const temp = array[i];
30+
array[i] = array[j];
31+
array[j] = temp;
32+
}
33+
}
34+
35+
function benchmark(method, n, values, values2, order) {
2236
const actual = new Set(values);
2337
// Prevent reference equal elements
24-
const deepCopy = JSON.parse(JSON.stringify(values2 ? values2 : values));
38+
let deepCopy = JSON.parse(JSON.stringify(values2));
39+
if (order === 'reversed') {
40+
deepCopy = deepCopy.reverse();
41+
} else if (order === 'random') {
42+
shuffleArray(deepCopy);
43+
}
2544
const expected = new Set(deepCopy);
2645
bench.start();
2746
for (let i = 0; i < n; ++i) {
@@ -30,39 +49,39 @@ function benchmark(method, n, values, values2) {
3049
bench.end(n);
3150
}
3251

33-
function main({ n, len, method, strict }) {
34-
const array = Array(len).fill(1);
52+
function main({ n, len, method, strict, order }) {
53+
const array = Array.from({ length: len }, () => '');
3554

3655
switch (method) {
3756
case 'deepEqual_primitiveOnly': {
3857
const values = array.map((_, i) => `str_${i}`);
39-
benchmark(strict ? deepStrictEqual : deepEqual, n, values);
58+
benchmark(strict ? deepStrictEqual : deepEqual, n, values, values, order);
4059
break;
4160
}
4261
case 'deepEqual_objectOnly': {
4362
const values = array.map((_, i) => [`str_${i}`, null]);
44-
benchmark(strict ? deepStrictEqual : deepEqual, n, values);
63+
benchmark(strict ? deepStrictEqual : deepEqual, n, values, values, order);
4564
break;
4665
}
4766
case 'deepEqual_mixed': {
4867
const values = array.map((_, i) => {
4968
return i % 2 ? [`str_${i}`, null] : `str_${i}`;
5069
});
51-
benchmark(strict ? deepStrictEqual : deepEqual, n, values);
70+
benchmark(strict ? deepStrictEqual : deepEqual, n, values, values, order);
5271
break;
5372
}
5473
case 'notDeepEqual_primitiveOnly': {
5574
const values = array.map((_, i) => `str_${i}`);
5675
const values2 = values.slice(0);
5776
values2[Math.floor(len / 2)] = 'w00t';
58-
benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2);
77+
benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2, order);
5978
break;
6079
}
6180
case 'notDeepEqual_objectOnly': {
6281
const values = array.map((_, i) => [`str_${i}`, null]);
6382
const values2 = values.slice(0);
6483
values2[Math.floor(len / 2)] = ['w00t'];
65-
benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2);
84+
benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2, order);
6685
break;
6786
}
6887
case 'notDeepEqual_mixed': {
@@ -71,7 +90,7 @@ function main({ n, len, method, strict }) {
7190
});
7291
const values2 = values.slice();
7392
values2[0] = 'w00t';
74-
benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2);
93+
benchmark(strict ? notDeepStrictEqual : notDeepEqual, n, values, values2, order);
7594
break;
7695
}
7796
default:

benchmark/assert/partial-deep-equal.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ function createSets(length, extraProps, depth = 0) {
6262
number: i,
6363
},
6464
['array', 'with', 'values'],
65-
!depth ? new Set([1, 2, { nested: i }]) : new Set(),
65+
!depth ? new Set([1, { nested: i }]) : new Set(),
6666
!depth ? createSets(2, extraProps, depth + 1) : null,
6767
]));
6868
}

0 commit comments

Comments
 (0)