news 2026/11/5 6:43:53

QuickJS 顶层 await 为何只执行两次:事件循环挂起原因与修复

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
QuickJS 顶层 await 为何只执行两次:事件循环挂起原因与修复

QuickJS 顶层 await 为何只执行两次:事件循环挂起原因与修复

【免费下载链接】quickjsPublic repository of the QuickJS Javascript Engine.项目地址: https://gitcode.com/gh_mirrors/qu/quickjs

在 QuickJS 里,同一段等待逻辑,写成顶层 await 只输出两次;写成.then()则每秒稳定打印一次。差别不在写法对错,而在事件循环对 Promise 的处理方式。

🔁 复现场景:触发 QuickJS 顶层 await 卡顿的三个条件

触发这个行为并不神秘:

const p = createPipe(); p.readHandler = onRead; // 读处理器一直未关闭 setTimeout(() => p.write("x"), 5000); // 5 秒后写入数据 // 主循环不断创建短期 Promise(1 秒超时后关闭管道) await waitForClose(p); // 顶层 await

三样东西要同时在场:管道的读处理器没有关掉;一个 5 秒的setTimeout悬着;主循环不断新建短期 Promise,每个都会在 1 秒后关管道。少掉任何一样,输出节奏通常不会坏。

.then() vs 顶层 await:两种写法的行为对照

事件序列完全一样,差别只在等待的写法:

写法实际表现
.then()链式每秒打印一次时间戳,节奏正常
顶层await只出现两行输出,都在 5 秒内落地

写法 A 相当于事件循环一直空转着等事;写法 B 相当于循环中途被按了暂停,直到 5 秒定时器到期才重新醒来。

🧩 QuickJS 顶层 await 卡住的原因:唤醒逻辑的三处变化

分歧来自 commit 8405876,它改了引擎判断"能不能睡"的方式。

顶层 await 的续体不再算待办信号

先给结论:8405876 之后,模块在顶层 await 处挂起时,引擎不再把它的续体记成一次待办活动。.then()链里每挂一个回调都是给循环的提示,循环会每个 tick 照常运转;换成 await 后,这个提示消失了,引擎判断无事可做,直接停 tick,只剩下 5 秒的定时器在撑着。

微任务冲刷的时机错位

Promise 结算、微任务队列冲刷时,顶层 await 的续体被排到了和.then()不同的执行点。引擎复查"还有没有活跃处理器"的时机因此被推迟,本该 1 秒内处理的短期 Promise 全部挤在这个空档里排队。

读处理器成了沉睡的守夜人

管道读处理器本该是维持循环的最后实体。旧逻辑里,数据一到它就叫醒循环;新逻辑里它的触发频率被压低,两次写入之间的 5 秒窗口内,循环几乎不发声。

🛠 修复路径与版本跟进

后续有单独的提交把这个行为修了回去,改动集中在三处:顶层 await 挂起/恢复的路径被重排,引擎在挂起后会重新检查待办状态;唤醒条件把顶层 await 的续体也算了进去;Promise 结算时的上下文恢复一并修正。升级时留意 Changelog 里 Promise 与事件循环相关的条目;落在 8405876 之后、修复之前的版本上,跑定时器加 await 的用例要格外小心。

📋 QuickJS 异步卡住排查:三条实战建议

  • 对时间敏感的链路用.then()链或显式回调,顶层 await 只做入口。
  • 在 Promise 超时回调里顺手关闭管道读处理器,干完活就注销,别留给循环空等。
  • 引擎升级后,先回归一批含定时器加 await 的异步用例,对比升级前后的输出节奏。

顶层 await 的卡顿,是引擎处理 Promise 与事件循环的一扇小窗。分清"处理器、定时器、微任务"这三者谁在维持循环醒来,这类问题基本就能定位。

【免费下载链接】quickjsPublic repository of the QuickJS Javascript Engine.项目地址: https://gitcode.com/gh_mirrors/qu/quickjs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/5 6:41:23

RealSense D455 三维建模避坑指南:从深度帧到点云

RealSense D455 三维建模避坑指南:从深度帧到点云 【免费下载链接】librealsense RealSense SDK 项目地址: https://gitcode.com/GitHub_Trending/li/librealsense 做完本文,你能用 librealsense 把 D455 的深度帧变成带颜色的三维点云&#xff0…

作者头像 李华
网站建设 2026/11/5 6:33:15

FreeTube播放器组件详解:打造流畅的视频播放体验

FreeTube播放器组件详解:打造流畅的视频播放体验 FreeTube作为一款注重隐私保护的开源YouTube应用程序,其核心竞争力之一在于强大的视频播放组件。本文将深入剖析FreeTube播放器的架构设计与核心功能,展示如何通过模块化组件实现流畅、个性化…

作者头像 李华
网站建设 2026/11/5 6:31:09

me3 开发者指南:从源码构建到 Windows 交叉编译的完整实战

【免费下载链接】me3 A framework for modding and instrumenting games. 项目地址: https://gitcode.com/gh_mirrors/me3/me3 点击查看 免费下载 me3 是一个用 Rust 编写的游戏 MOD 加载与插桩框架(A framework for modding and instrumenting games&a…

作者头像 李华
网站建设 2026/11/5 6:28:40

工业级温度采集系统:ADS122U04IPWR与STM32F413RH硬核搭配

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华