基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
技术实践2026-10-30 05:56

10MB JSON 实测:异步读取仍会阻塞解析

dev.to · AI#性能优化#工作线程#事件循环
Editor brief · 编辑速览

作者比较 Node.js 同步读取、异步读取后解析和工作线程解析:前两种均在解析阶段阻塞事件循环约 70—90 毫秒。工作线程保持了主线程响应,但单次解析总耗时增加约 100—200 毫秒。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

把文件读取改成 await,并不能让 JSON.parse 也变成异步。作者用同一份约 10MB 的 JSON 文件比较了三条处理路径:同步读取并解析、异步读取后解析、交给 Worker 读取并解析。前两条都会卡住 Node 主线程,第三条能保住响应能力,却增加了总耗时。

这组实验值得看的地方,是它把「任务多久完成」和「期间还能不能处理别的事」分开测量了。对 Node 服务来说,这两个指标经常决定着不同的技术选择。

为什么异步读取救不了 JSON.parse

测试文件包含 40,000 条商品数据,每条都有 id、SKU、标题、价格、标签、库存标记和 metadata。整个数组经 JSON.stringify 序列化后,文件大小为 10,403,316 字节,作者记作 10.4MB。

三条路径的区别在于,哪些工作留在主线程:

  • fs.readFileSync 读取文件,再调用 JSON.parse,两步都同步执行。
  • fs.promises.readFile 异步读取文件,拿到结果后仍由主线程执行 JSON.parse。
  • 通过 worker_threads 创建 Worker,在工作线程内完成读取和解析,再向主线程返回行数。

第二条路径容易让人误判。文件读取期间,主线程确实可以处理其他任务;但读取完成后,把字符串转换成 JavaScript 对象,仍是一段需要连续占用 CPU 的同步工作。await 只能等待前面的异步操作,不能改变后面函数的执行方式。

异步读取解决的是等待磁盘时的阻塞,无法消除 JSON.parse 占用主线程的时间。

作者用一个每 1ms 调度一次的 setInterval 观察响应能力。如果主线程正在执行同步解析,定时器回调就没有机会运行。这比只看解析函数花了多久,更接近服务端真正关心的问题:解析期间,其他请求有没有机会被处理。

Worker 保住了响应,为什么完成得更慢

每条路径各跑三次,同步读取路径中,单独的 JSON.parse 耗时分别为 79.42ms、84.83ms、93.13ms。三次解析窗口内,定时器回调计数都是 0。

异步读取路径在等待 I/O 时能执行 17 到 23 次回调,但进入解析后同样停住。三次解析耗时为 71.33ms、83.9ms、73.97ms,与同步路径处于相近范围。

所以,不能因为磁盘读取已经异步化,就认为整个数据加载过程都不会阻塞。这个文件的解析成本已经足以主导任务耗时,换一种读取方式没有解决主要矛盾。

Worker 路径中,主线程定时器分别执行了 168、207、259 次。这支持作者最重要的观察:解析搬走以后,主线程仍有机会持续运行其他任务。

代价也很明确。Worker 内部测得的解析时间分别为 109.18ms、160.36ms、143.5ms,反而比主线程上的同步解析更慢。从主线程开始创建 Worker,到收到结果的端到端耗时,则分别达到 205.66ms、258.38ms、319.76ms。

按作者的概括,整个任务约慢了两到三倍,多付出了约 100 到 200ms。

这里采用的是每次任务新建一个 Worker 的方式,需要创建线程和新的 V8 isolate,也就是相对独立的 JavaScript 执行环境。任务完成前,还要经历文件路径传入和结果消息返回。对于一次性解析,这些固定开销很难摊薄。

还有一个容易遗漏的边界:Worker 只返回了解析后的行数。

如果实际业务需要把整个商品对象数组交回主线程,通信和数据交接的成本就不再等同于返回一个数字。原文没有测试这种情况,因此这组端到端耗时不能直接当成「主线程拿到完整解析结果」的成本。

应该先决定保护谁,再决定用不用 Worker

如果程序只在启动时读一次配置或数据文件,尚未接收请求,也没有其他任务依赖主线程响应,那么同步处理可以是合理选择。在作者这次测试里,它完成得更快,也省去了线程管理。

不过,「启动时」不自动等于「没有其他工作」。假如进程已经开放健康检查,或者正在执行其他初始化任务,同步解析仍可能影响这些任务。关键是解析发生的那个时间窗口里,究竟有没有事情需要及时执行。

对于已经处理并发请求的 Node 服务,取舍会不同。单个任务多花一些时间,可能换来其他请求继续被调度。桌面应用中承担界面职责的线程,以及同时处理定时任务的进程,也有类似需求。

Worker 的价值,是让主线程保持可用;任务本身是否更快,需要另算。

如果需要反复解析文件,作者提出可以复用长期运行的 Worker pool,把启动成本分摊到多个任务。但他们没有测试线程池,因此不能用本文数据推断复用后的每次开销,更不能直接宣称吞吐量会提高多少。

文件大小同样影响判断。作者称,同一机器上的 1MB 文件只需几毫秒;对 50MB、100MB 文件,则预期同步阻塞可能进入数百毫秒甚至更久。后两者没有给出具体测量结果。对象形状和嵌套深度也会改变解析成本,不能把 10MB 的数据简单按比例放大。

我的判断

我认同作者把响应能力与完成时间分开讨论。这比一句「大 JSON 用 Worker」更有用,也比只强调异步读取更准确。

但这是一组范围有限的实验,不足以给出通用阈值。

首先,原文没有交代 Node 版本、硬件配置、操作系统,也没有提供完整测试代码。每条路径只有三次结果,能说明这次运行中的明显差异,无法据此判断不同环境下的稳定分布。

其次,每次重新从磁盘读取文件,不代表绕过了操作系统文件缓存。作者强调没有复用内存中的文件副本,但没有说明如何控制缓存,因此「不是预热后的最佳情况」还不能被严格确认。

定时器指标也需要收紧解释。1ms 是请求的调度间隔,并不保证回调严格每毫秒执行一次。168、207、259 次回调说明主线程持续获得了执行机会;但仅凭总次数,不能证明作者所说的「零丢失」或全程没有明显间隙。后者需要回调时间戳、最大间隔等证据。

此外,总耗时与 Worker 内部解析时间之间的差值,不能全部归为启动成本;它还包含其他未单独拆出的工作。作者观察到了额外开销,但没有完整分解来源。

与流式解析相比,Worker 也只是另一种取舍:前者尝试改变数据消费方式,后者把现有同步工作搬到其他线程。原文没有测试流式方案,也没有比较内存占用。对于能够逐条处理的数据导入任务,不能据此认定 Worker 就是最佳选择。

能拿来做什么

  • 检查 Node 项目里读取大文件的调用链,尤其是 fs.promises.readFile 后紧接 JSON.parse 的位置。把读取与解析分别计时,确认真正占用主线程的是哪一步。
  • 对处理商品数据或批量导入的服务,同时测任务总耗时和其他请求的延迟。是否值得增加 Worker 开销,应由并发任务受到的影响决定。
  • 如果准备使用 Worker,按业务真实需要返回数据。只返回行数、返回汇总结果、返回完整对象数组,是不同的测量场景,应分别验证。
  • 对反复执行的解析任务,比较每次新建 Worker 与复用 Worker pool 的表现;对一次性的启动加载,则先确认服务是否已经需要响应请求,再决定是否接受同步阻塞。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
用验收测试检查代理令牌能否被盗用
下一篇
A2A 权限设计:发现、身份与授权分开判断

资讯速览

dev.to · AI · 2026-10-30 05:56

AI 评分 8.0 / 10

相关标签

#性能优化#工作线程#事件循环

继续阅读

  • 代理停用测试要覆盖凭证、授权与队列
  • 用验收测试检查代理令牌能否被盗用
  • A2A 权限设计:发现、身份与授权分开判断
  • 语音 Agent 如何明确表达未知信息
  • 给 AI 代码设置凭证据放行的质量门禁