Generator函数可边流式接收JSON边解析,通过状态机跟踪括号层级与字符串状态,每完成一个原子单元即yield,避免主线程阻塞,适用于大型图表、日志等场景。

用 Generator 函数无损解析超长 JSON 文本,核心是“不等全部下载完、不等完整字符串拼好”,而是边接收流式数据边识别结构边界,把一个巨型 JSON 拆成可逐项处理的原子单元。这能避免 JSON.parse() 卡住主线程导致页面假死,尤其适用于渲染大型图表、日志列表或实时数据看板。
利用 Fetch + ReadableStream 实现边下载边喂入
浏览器 Fetch 的 response.body 是原生可读流,必须配合 getReader() 逐块读取字节,再交由生成器做状态机解析:
- 调用
fetch(url).then(r => r.body.getReader())获取流读取器 - 用
reader.read()循环读取{ value: Uint8Array, done: boolean }片段 - 将每块二进制转为字符串(注意 UTF-8 多字节边界,推荐用
TextDecoder) - 把连续字符串喂给一个内部维护解析状态的 Generator,它只在完整 JSON 项(如一个对象或数组元素)就绪时才
yield
用状态机生成器识别 JSON 边界
不能直接对碎片字符串反复调用 JSON.parse——会报错或截断。需手写轻量状态机,逐字符推进并跟踪括号层级和引号状态:
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
- 初始化状态:
depth = 0(对象/数组嵌套深度),inString = false,escape = false - 遇到
{或[且不在字符串中 →depth++ - 遇到
}或]且不在字符串中 →depth--,若depth === 0则当前已构成一个完整项,yield当前累积内容 - 遇到
"且未被转义 → 切换inString;遇到\→ 切换escape - 每次 yield 后清空缓冲区,继续处理后续字符
对接前端渲染链:用 for...of 按需消费
生成器产出的是一个个独立 JSON 值(如每个用户对象),可直接接入现代前端框架的响应式更新机制:
- 用
for await (const item of parseJsonStream(response))遍历(注意需 async generator) - 每拿到一个
item,立即触发局部 DOM 更新(如list.push(item)+requestIdleCallback批量渲染) - 支持中途取消:外部
break时,生成器自动停止,流读取器可reader.cancel()释放连接 - 错误处理放在生成器内部
try/catch,向调用方抛出结构化错误(如 “第12489字符处JSON格式异常”)
补充要点:避免常见陷阱
实际落地时几个细节决定成败:
- 确保流解码不丢字符:用
new TextDecoder('utf-8', { fatal: false })忽略非法字节,防止整个流中断 - 缓冲区不要无限增长:设置最大未闭合深度(如 depth > 100 强制报错),防恶意嵌套攻击
- 不依赖第三方大包:像
json-bigint这类库默认要求完整输入,需改造其 parser 为可恢复式,或改用更轻量的状态机实现 - 服务端配合:返回时启用
Transfer-Encoding: chunked,并确保每块至少包含一个完整 JSON 项(如以\n分隔的 NDJSON)可大幅简化前端逻辑










