-
-
Notifications
You must be signed in to change notification settings - Fork 240
Description
I have done some small research on the difference between the json and the advanced serialization formats of the ipc feature. I just wanted to share them for future reference, so will close this issue.
Speed
Generally speaking, json is ~1.3x faster on small values, while advanced is up to 6x faster faster on big values. This aligns with what the Node.js PR that introduced this feature is benchmarking too. Which is a bit more nuanced than what the documentation is mentioning.
Additionally, performance may not be equivalent to that of JSON, depending on the structure of the passed data. Therefore, this feature requires opting in by setting the serialization option to 'advanced' when calling child_process.spawn() or child_process.fork().
Using my machine (Node 21, Ubuntu 23.10), advanced is:
- 1.3x slower: on boolean, number, null, short string, empty array, any array with non-random items, empty object
- same speed: 1KB string, array with 50 random items, object with 10_000 random fields
- 1.7x faster: object with 1_000_000 random fields
- 2.5x faster: array with 1_000_000 random items
- 6x faster: 1MB string
Benchmark code:
import {spawn} from 'node:child_process'
import {once} from 'node:events'
const loopCount = 1e3
const value = '.'.repeat(1e6)
for (const serialization of ['json', 'advanced']) {
const childProcess = spawn('node', ['child.js'], {stdio: ['pipe', 'pipe', 'pipe', 'ipc'], serialization});
await once(childProcess, 'message')
console.time(serialization)
for (let i = 0; i < loopCount; i += 1) {
childProcess.send(value)
await once(childProcess, 'message')
}
console.timeEnd(serialization)
childProcess.disconnect()
}Compatibility
The documentation mentions that:
However, this format is not a full superset of JSON, and e.g. properties set on objects of such built-in types will not be passed on through the serialization step.
I have tried many values of different types. The result is this:
advancedkeeps regExps,Map,Set,ArrayBuffer,ArrayBufferView,BufferandUint8Arrayas is. Those values are serialized to empty objects withjsonadvancedkeepsDateinstances as is. Those are serialized to strings withjson.advancedsupportsundefinedand bigint, except at the top-level. Those values throw withjson.advancedkeepsundefinedobject properties as is. Those properties are filtered out withjson.advancedsupportsNaN,Infinity. Alsoundefinedarray items. Those values are serialized tonullwithjson.advancedsupports circular references. Those values throw withjson.advancedhas a generic (not full) support forErrorinstances. Those values are serialized to empty objects withjson.advancedthrows if an object/array contains functions or symbols. Those properties are filtered out (but do not error) withjson.- both formats throw on symbols, functions, promises, proxies,
Intl.* - both formats ignore symbol keys, setters, getters, property descriptors, inherited properties and non-enumerable properties in objects
So I would personally consider advanced to be mostly a superset of json, which the following caveats:
- Objects/arrays containing functions, symbols or promises throw with
advanced, while they are ignored withjson. - Objects with
toJSON()throw, while they are handled byjson - Dates are kept as is instead of being converted to strings
I wanted to share this information for any future discussion around that feature.