feat: add object hashing benchmarking
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Sat, 20 Apr 2024 15:02:13 +0000 (17:02 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Sat, 20 Apr 2024 15:02:13 +0000 (17:02 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
deep-clone-object.mjs
deep-merge-object.mjs
is-empty-object.mjs
object-hash.mjs [new file with mode: 0644]
package.json
pnpm-lock.yaml
shallow-clone-object.mjs

index 00753e2f439ed0df4c3d7c0250cdf4f687cd2606..40b508da1505dd0b43984de6c62bff34f5b1442f 100644 (file)
@@ -11,22 +11,22 @@ const object = generateRandomObject()
 
 group(`Deep clone object with ${Object.keys(object).length} keys`, () => {
   bench('JSON stringify/parse', (obj = object) => {
-    const objCloned = JSON.parse(JSON.stringify(obj))
+    JSON.parse(JSON.stringify(obj))
   })
   bench('structuredClone', (obj = object) => {
-    const objCloned = structuredClone(obj)
+    structuredClone(obj)
   })
   bench('lodash cloneDeep', (obj = object) => {
-    const objCloned = _.cloneDeep(obj)
+    _.cloneDeep(obj)
   })
   bench('rambda clone', (obj = object) => {
-    const objCloned = rambdaClone(obj)
+    rambdaClone(obj)
   })
   bench('just-clone', (obj = object) => {
-    const objCloned = clone(obj)
+    clone(obj)
   })
   bench('deep-clone', (obj = object) => {
-    const objCloned = deepClone(obj)
+    deepClone(obj)
   })
 })
 
index 50cc13cb4cbe60341f815d6310fab4dacaac0b01..a33dc2160d1b3547f89d0d54adf63d585861bfb8 100644 (file)
@@ -15,13 +15,13 @@ group(
   } keys, object with ${Object.keys(objectToMerge).length} keys`,
   () => {
     bench('lodash merge', (obj = object) => {
-      const objMerged = _.merge(obj, objectToMerge)
+      _.merge(obj, objectToMerge)
     })
     bench('rambda mergeDeepRight', (obj = object) => {
-      const objMerged = mergeDeepRight(obj, objectToMerge)
+      mergeDeepRight(obj, objectToMerge)
     })
     bench('deepmerge', (obj = object) => {
-      const objMerged = deepMerge(obj, objectToMerge)
+      deepMerge(obj, objectToMerge)
     })
   }
 )
index 2d788816db5f5fb3afdece0a6e34a0861c23e4c4..842ae4a9ec812ee95e8f4e94e2445809e51f2305 100644 (file)
@@ -22,10 +22,10 @@ group(`Is empty object with ${Object.keys(object).length} keys`, () => {
     return obj?.constructor === Object && Object.keys(obj).length === 0
   })
   bench('lodash isEmpty', (obj = object) => {
-    return _.isEmpty(obj)
+    _.isEmpty(obj)
   })
   bench('rambda isEmpty', (obj = object) => {
-    return isEmpty(obj)
+    isEmpty(obj)
   })
 })
 
diff --git a/object-hash.mjs b/object-hash.mjs
new file mode 100644 (file)
index 0000000..d20a317
--- /dev/null
@@ -0,0 +1,24 @@
+import hashObject from 'hash-object'
+import { hasher } from 'node-object-hash'
+import hash from 'object-hash'
+import { bench, group, run } from 'tatami-ng'
+
+import { generateRandomObject } from './benchmark-utils.mjs'
+
+const object = generateRandomObject()
+
+group(`Hash object with ${Object.keys(object).length} keys`, () => {
+  bench('hash-object', (obj = object) => {
+    return hashObject(obj, { algorithm: 'sha256' })
+  })
+  bench('node-object-hash', (obj = object) => {
+    return hasher({ alg: 'sha256' }).hash(obj)
+  })
+  bench('object-hash', (obj = object) => {
+    return hash(obj, { algorithm: 'sha256' })
+  })
+})
+
+await run({
+  units: true
+})
index fd29383ae1ae7d633a52cb98f64609579715920e..74cf3278d5d2fcbc30db52180d67695f2d9578db 100644 (file)
     "benchmark:busy-wait": "node busy-wait.mjs",
     "benchmark:deep-clone-object": "node deep-clone-object.mjs",
     "benchmark:deep-merge-object": "node deep-merge-object.mjs",
-    "benchmark:json-stringify": "node json-stringify.mjs",
     "benchmark:empty-array": "node empty-array.mjs",
     "benchmark:shallow-clone-object": "node shallow-clone-object.mjs",
     "benchmark:is-empty-object": "node is-empty-object.mjs",
     "benchmark:is-undefined": "node is-undefined.mjs",
+    "benchmark:json-stringify": "node json-stringify.mjs",
     "benchmark:quick-select": "node quick-select.mjs",
     "benchmark:max": "node max.mjs",
     "benchmark:min": "node min.mjs",
+    "benchmark:object-hash": "node object-hash.mjs",
     "benchmark:promise-handling": "node promise-handling.mjs",
     "benchmark:fibonacci": "node fibonacci.mjs",
     "benchmark:random": "node random.mjs",
   "dependencies": {
     "deep-clone": "^4.0.0",
     "deepmerge": "^4.3.1",
+    "hash-object": "^5.0.1",
     "just-clone": "^6.2.0",
     "lodash": "^4.17.21",
+    "node-object-hash": "^3.0.0",
+    "object-hash": "^3.0.0",
     "rambda": "^9.2.0",
     "tatami-ng": "^0.4.4",
     "uuid": "^9.0.1"
index 2f243966e910b17bcaab63ff07bdb8a539e3e5d8..80aa40508374e992d407b92e4bc801c5faa80650 100644 (file)
@@ -17,12 +17,21 @@ importers:
       deepmerge:
         specifier: ^4.3.1
         version: 4.3.1
+      hash-object:
+        specifier: ^5.0.1
+        version: 5.0.1
       just-clone:
         specifier: ^6.2.0
         version: 6.2.0
       lodash:
         specifier: ^4.17.21
         version: 4.17.21
+      node-object-hash:
+        specifier: ^3.0.0
+        version: 3.0.0
+      object-hash:
+        specifier: ^3.0.0
+        version: 3.0.0
       rambda:
         specifier: ^9.2.0
         version: 9.2.0
@@ -517,6 +526,10 @@ packages:
       supports-color:
         optional: true
 
+  decircular@0.1.1:
+    resolution: {integrity: sha512-V2Vy+QYSXdgxRPmOZKQWCDf1KQNTUP/Eqswv/3W20gz7+6GB1HTosNrWqK3PqstVpFw/Dd/cGTmXSTKPeOiGVg==}
+    engines: {node: '>=18'}
+
   deep-clone@4.0.0:
     resolution: {integrity: sha512-bMvDVR8GiGCGHT4SgqXyXDD9Zmo3kv9YLq8aSO2xslP97A3mFkpNBg+t+fjXERvewzhmtk9efvL+V52iVkD0lg==}
 
@@ -916,6 +929,10 @@ packages:
     resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
     engines: {node: '>= 0.4'}
 
+  hash-object@5.0.1:
+    resolution: {integrity: sha512-iaRY4jYOow1caHkXW7wotYRjZDQk2nq4U7904anGJj8l4x1SLId+vuR8RpGoywZz9puD769hNFVFLFH9t+baJw==}
+    engines: {node: '>=18'}
+
   hasown@2.0.2:
     resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
     engines: {node: '>= 0.4'}
@@ -1042,10 +1059,18 @@ packages:
     resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
     engines: {node: '>=8'}
 
+  is-obj@3.0.0:
+    resolution: {integrity: sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==}
+    engines: {node: '>=12'}
+
   is-path-inside@3.0.3:
     resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
     engines: {node: '>=8'}
 
+  is-plain-obj@4.1.0:
+    resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
+    engines: {node: '>=12'}
+
   is-regex@1.1.4:
     resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
     engines: {node: '>= 0.4'}
@@ -1265,6 +1290,10 @@ packages:
   natural-compare@1.4.0:
     resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
 
+  node-object-hash@3.0.0:
+    resolution: {integrity: sha512-jLF6tlyletktvSAawuPmH1SReP0YfZQ+tBrDiTCK+Ai7eXPMS9odi5xW/iKC7ZhrWJJ0Z5xYcW/x+1fVMn1Qvw==}
+    engines: {node: '>=16', pnpm: '>=8'}
+
   npm-run-path@5.3.0:
     resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -1273,6 +1302,10 @@ packages:
     resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
     engines: {node: '>=0.10.0'}
 
+  object-hash@3.0.0:
+    resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
+    engines: {node: '>= 6'}
+
   object-inspect@1.13.1:
     resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
 
@@ -1540,6 +1573,10 @@ packages:
     resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
     engines: {node: '>=18'}
 
+  sort-keys@5.0.0:
+    resolution: {integrity: sha512-Pdz01AvCAottHTPQGzndktFNdbRA75BgOfeT1hH+AMnJFv8lynkPi42rfeEhpx1saTEI3YNMWxfqu0sFD1G8pw==}
+    engines: {node: '>=12'}
+
   spdx-exceptions@2.5.0:
     resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==}
 
@@ -1659,6 +1696,10 @@ packages:
     resolution: {integrity: sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==}
     engines: {node: '>=6'}
 
+  type-fest@4.15.0:
+    resolution: {integrity: sha512-tB9lu0pQpX5KJq54g+oHOLumOx+pMep4RaM6liXh2PKmVRFF+/vAtUP0ZaJ0kOySfVNjF6doBWPHhBhISKdlIA==}
+    engines: {node: '>=16'}
+
   typed-array-buffer@1.0.2:
     resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
     engines: {node: '>= 0.4'}
@@ -2264,6 +2305,8 @@ snapshots:
     dependencies:
       ms: 2.1.2
 
+  decircular@0.1.1: {}
+
   deep-clone@4.0.0: {}
 
   deep-is@0.1.4: {}
@@ -2795,6 +2838,13 @@ snapshots:
     dependencies:
       has-symbols: 1.0.3
 
+  hash-object@5.0.1:
+    dependencies:
+      decircular: 0.1.1
+      is-obj: 3.0.0
+      sort-keys: 5.0.0
+      type-fest: 4.15.0
+
   hasown@2.0.2:
     dependencies:
       function-bind: 1.1.2
@@ -2901,8 +2951,12 @@ snapshots:
 
   is-obj@2.0.0: {}
 
+  is-obj@3.0.0: {}
+
   is-path-inside@3.0.3: {}
 
+  is-plain-obj@4.1.0: {}
+
   is-regex@1.1.4:
     dependencies:
       call-bind: 1.0.7
@@ -3115,12 +3169,16 @@ snapshots:
 
   natural-compare@1.4.0: {}
 
+  node-object-hash@3.0.0: {}
+
   npm-run-path@5.3.0:
     dependencies:
       path-key: 4.0.0
 
   object-assign@4.1.1: {}
 
+  object-hash@3.0.0: {}
+
   object-inspect@1.13.1: {}
 
   object-keys@1.1.1: {}
@@ -3391,6 +3449,10 @@ snapshots:
       ansi-styles: 6.2.1
       is-fullwidth-code-point: 5.0.0
 
+  sort-keys@5.0.0:
+    dependencies:
+      is-plain-obj: 4.1.0
+
   spdx-exceptions@2.5.0: {}
 
   spdx-expression-parse@4.0.0:
@@ -3529,6 +3591,8 @@ snapshots:
 
   type-fest@0.3.1: {}
 
+  type-fest@4.15.0: {}
+
   typed-array-buffer@1.0.2:
     dependencies:
       call-bind: 1.0.7
index e01a3c4f61f454b17a575dce06a1620ff6a7ab47..f5c79c3bf6542e08d246b3df2012a928eef17a58 100644 (file)
@@ -9,16 +9,16 @@ const object = generateRandomObject()
 
 group(`Shallow clone object with ${Object.keys(object).length} keys`, () => {
   bench('Spread', () => {
-    const objClone = { ...object }
+    return { ...object }
   })
   bench('Object assign', () => {
-    const objClone = Object.assign({}, object)
+    return Object.assign({}, object)
   })
   bench('lodash clone', () => {
-    const objClone = _.clone(object)
+    _.clone(object)
   })
   bench('rambda assoc', () => {
-    const objClone = assoc(object)
+    assoc(object)
   })
 })