Skip to content

Instantly share code, notes, and snippets.

@fabiospampinato
Created June 24, 2026 11:30
Show Gist options
  • Select an option

  • Save fabiospampinato/77d207abaf3a358081ccd65175a29137 to your computer and use it in GitHub Desktop.

Select an option

Save fabiospampinato/77d207abaf3a358081ccd65175a29137 to your computer and use it in GitHub Desktop.
are-deeply-equal vs object-identity bench
/* Mini benchmark: are-deeply-equal vs object-identity */
import areDeeplyEqual from 'are-deeply-equal';
import { identify } from 'object-identity';
/* CONTENDERS */
// are-deeply-equal: direct deep comparison (can short-circuit)
const isEqualDirect = ( a, b ) => areDeeplyEqual ( a, b );
// object-identity: equality via a canonical identity string (no short-circuit)
const isEqualIdentity = ( a, b ) => identify ( a ) === identify ( b );
/* FIXTURES */
const makeSimple = () => ({
id: 42,
name: 'fixture',
active: true,
ratio: 3.14,
tags: [ 'a', 'b', 'c' ],
meta: { created: 1700000000, nested: { x: 1, y: 2, z: [ 4, 5, 6 ] } }
});
const makeBig = () => {
const obj = {};
for ( let i = 0; i < 300; i++ ) obj[`key_${i}`] = i;
return obj;
};
const makeDeep = () => {
let node = { value: 0 };
for ( let i = 1; i < 200; i++ ) node = { value: i, child: node };
return node;
};
const makeLeafy = () => {
const arr = [];
for ( let i = 0; i < 1000; i++ ) arr.push ( i % 2 ? `s${i}` : i );
return arr;
};
/* HELPERS */
// Mutate the very last leaf, so a difference only shows up at the deepest point
const breakLast = value => {
if ( Array.isArray ( value ) ) {
const out = value.slice ();
out[out.length - 1] = '__DIFFERENT__';
return out;
}
if ( value && typeof value === 'object' ) {
const keys = Object.keys ( value );
const lastKey = keys[keys.length - 1];
return { ...value, [lastKey]: '__DIFFERENT__' };
}
return '__DIFFERENT__';
};
const bench = ( name, fn, iterations ) => {
for ( let i = 0; i < Math.min ( iterations, 5000 ); i++ ) fn (); // warmup
const start = process.hrtime.bigint ();
for ( let i = 0; i < iterations; i++ ) fn ();
const elapsedMs = Number ( process.hrtime.bigint () - start ) / 1e6;
const opsPerSec = iterations / ( elapsedMs / 1000 );
return { name, elapsedMs, opsPerSec };
};
const fmt = n => n.toLocaleString ( 'en-US', { maximumFractionDigits: 0 } );
const run = ( title, a, b, expected, iterations ) => {
if ( isEqualDirect ( a, b ) !== expected || isEqualIdentity ( a, b ) !== expected ) {
console.log ( ` ⚠ ${title}: contenders disagree (expected ${expected}), skipping` );
return;
}
const r1 = bench ( 'are-deeply-equal', () => isEqualDirect ( a, b ), iterations );
const r2 = bench ( 'object-identity ', () => isEqualIdentity ( a, b ), iterations );
const winner = r1.opsPerSec > r2.opsPerSec ? r1 : r2;
const loser = r1.opsPerSec > r2.opsPerSec ? r2 : r1;
const factor = ( winner.opsPerSec / loser.opsPerSec ).toFixed ( 2 );
console.log ( `▸ ${title} (${fmt ( iterations )} iterations)` );
console.log ( ` ${r1.name} ${fmt ( r1.opsPerSec ).padStart ( 12 )} ops/s (${r1.elapsedMs.toFixed ( 1 )} ms)` );
console.log ( ` ${r2.name} ${fmt ( r2.opsPerSec ).padStart ( 12 )} ops/s (${r2.elapsedMs.toFixed ( 1 )} ms)` );
console.log ( ` → ${winner.name.trim ()} is ${factor}× faster\n` );
};
/* RUN */
const cases = [
{ label: 'simple', make: makeSimple, iterations: 200000 },
{ label: 'big (300 keys)', make: makeBig, iterations: 50000 },
{ label: 'deep (200 levels)', make: makeDeep, iterations: 50000 },
{ label: 'leafy (1000 items)', make: makeLeafy, iterations: 50000 }
];
console.log ( '\n=== EQUAL path (values are deeply equal) ===\n' );
for ( const { label, make, iterations } of cases ) {
run ( label, make (), make (), true, iterations );
}
console.log ( '=== NOT-EQUAL path (differ only at the deepest/last leaf) ===\n' );
for ( const { label, make, iterations } of cases ) {
run ( label, make (), breakLast ( make () ), false, iterations );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment