How we made JSON.stringify more than twice as fast
JSON.stringify as a bottleneck (especially in Node)
- Multiple commenters say JSON.stringify is often a top CPU cost in Node services, especially GraphQL/Apollo/Express where entire responses are serialized at once and not streamed.
- JSON encoding is described as a major impediment to interprocess communication: offloading work to workers often just trades event-loop stalls for main-thread CPU spikes due to serialization.
- Some note that in Amdahl’s Law terms stringify can dominate the “sequential” part of Node workloads. Others emphasize that JSON serialization is inherently expensive across ecosystems, not just JS.
Concurrency, Node’s model, and IPC
- A long thread debates Node’s cooperative single-threaded model vs preemptive multitasking (Go, JVM).
- Critics argue Node/JS were not designed for parallelism; retrofitting proper multithreading is seen as extremely hard and possibly not worth the cost.
- Some defend Node for IO-heavy “CRUD-style” services, saying it scales well via process-per-CPU and simple async, but acknowledge it struggles with heavy CPU or large JSON operations.
- Several point out that structuredClone / postMessage use binary serialization internally and can be faster than JSON, but benchmarks and semantics vary; with the new optimizations JSON may again be faster in many cases.
Alternatives, streaming, and binary formats
- Suggestions include: streaming JSON serialization on the JVM, using TypedArrays/SharedArrayBuffers/DataView, or going to WebAssembly and working on buffers directly.
- Protobuf is discussed: some value its backward/forward-compatible binary wire format; others prefer JSON’s simplicity and human-readability, arguing JSON can also be evolved safely with conventions.
- There’s interest in hypothetical
JSON.toBufferor JSON streaming APIs to reduce intermediate string allocations.
Correctness: floats and numbers
- Several comments dive into float→string→float roundtripping, mentioning modern algorithms (Dragonbox, Steele & White, Burger & Dybvig) and the need for unique decimal representations.
- People note JSON itself doesn’t mandate IEEE754; real-world parsers in different languages (Java, C#, Python, etc.) make different choices, which can introduce subtle interoperability issues.
Fast path, side effects, and safety
- Discussion of V8’s new “fast path” centers on its restrictions: no replacer/space, no custom toJSON, no getters or index-like keys, etc., to avoid side effects and complexity.
- Commenters explain that even seemingly benign getters can allocate and trigger GC, so anything with potential side effects must fall back to the general slow path.
- Some ask whether this optimization was security-tested; others respond that JSON.stringify is heavily tested already.
Perspectives on JS, V8, and types
- V8 is widely praised as “insanely fast,” with comments about billion-dollar-level engineering.
- At the same time, many criticize JavaScript’s dynamic semantics, messy ecosystem, and difficulty of adding sound types or real parallelism.
- Ideas floated: stricter modes beyond "use strict", a soundly-typed JS/TS subset with AOT compilation (possibly to WASM), and better type hints for VMs.
Miscellaneous
- Some discuss the segmented-buffer/rope-like implementation as a big win, reminiscent of userland libraries but now in-engine.
- There’s curiosity about effects on structuredClone performance and on idioms like
JSON.parse(JSON.stringify(obj))vs structuredClone. - Minor tangents cover Node vs other languages (Python, Go, Java, LuaJIT), the naming of
stringify, and how small per-call gains matter at global scale.