跪拜 Guibai
← All articles
Frontend

Streaming LLM JSON: The 2026 Frontend Hurdle Is Rendering Before the Closing Brace

By 涛涛ing ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

As AI outputs shift from chat text to structured cards, tables, and tool-call arguments, a frontend that waits for the complete JSON can leave users staring at a blank screen for the entire 5–15 second generation. Stream rendering is only meaningful if the UI updates early; following the article's completion, throttling, and safety rules turns that wait into a smooth, incremental display without letting half-formed data corrupt backend state.

Summary

A model generating a complete structured JSON can take 5 to 15 seconds and emit hundreds of tokens. If the frontend waits for the final `}` before calling `JSON.parse()`, users stare at a blank card for the whole duration, and streaming becomes pointless. The article breaks the fix into three engineering hurdles: completing truncated JSON, throttling UI updates, and keeping partial data from being misused.

Completion requires a stack-based parser that strips dangling keys, closes unterminated strings, and balances braces. The `partial-json` library does this with an `Allow` bitmask that can suppress half-formatted numbers to prevent flicker. Throttling is the next problem: parsing every chunk makes a 27,000-chunk stream take 32.7 seconds (O(n²) behavior); batching to every 50 chunks with `requestAnimationFrame` or a 50–80ms timer cuts that to 0.53 seconds. Finally, partial objects look identical to real data, so the article lays down three safety lines: never submit partial data to a database or trigger a tool call until a full parse passes, and always validate URL schemes to block `javascript:` payloads.

Takeaways
— A complete structured JSON from an LLM typically costs hundreds of tokens and 5–15 seconds; rendering only after the final `}` erases the benefit of streaming.
— The SSE envelope is separate from the inner business JSON; buffer line-splitting works for the envelope, but the inner JSON needs a dedicated completion parser.
— A stack-based completion script can trim dangling keys/commas, close unterminated strings, and append missing brackets; 35 lines of code demonstrate the core, production use `partial-json`.
— Per-chunk `JSON.parse()` on a 27,000-chunk stream takes roughly 32.7 seconds; throttling to every 50 chunks with `requestAnimationFrame` or a 50–80ms timer drops it to about 0.53 seconds.
— Partial JSON must only be used for display; write to DB, form submission, or tool execution requires `done === true` plus a full `JSON.parse` or `zod.safeParse` check.
— Structured doesn't mean safe: URL fields need protocol validation against `javascript:` pseudo-protocols, and text fields should use text interpolation, not `innerHTML`.
Conclusions

Streaming structured output turns the frontend into a speculative parser that must guess the model's intent from a truncated token stream; that guesswork is why completion, throttling, and safety rules have to be designed together.

The throttling numbers show that per-chunk parsing is O(n²) and unusable at stream scale; batching parses to the display refresh interval is what keeps a long stream interactive, not a faster parse function.

The biggest risk is not a parse error but a 'good enough' partial object that passes for complete data, which is why the article's safety lines treat any stream that hasn't emitted `done:true` as untrusted.

Concepts & terms
SSE envelope
The top part of the SSE response envelope. Each line ends with a newline and contains the `data:` field; the inner business JSON is built by concatenating the `delta.content` fields across all chunks.
partial-json
A zero-dependency npm package that parses incomplete JSON strings and returns partially constructed objects. Its `Allow` bitmask controls which data types can be left in a partial state, letting you disable half-baked numbers to prevent flicker.
JSON completion/repair
The process of turning a truncated or malformed JSON string into a valid object by trimming dangling tokens, closing unterminated strings, and balancing brackets. The article shows a stack-based algorithm and also mentions jsonrepair as a more tolerant alternative.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗