当前位置: 首页 > news >正文

一个 setTimeout 引出了事件循环问题,这个事件循环到底是个啥?

昨天,在使用 Browser-Bridge 的时候,我发现每次执行浏览器指令时都是数据返回后还会等几秒才结束命令行。我就奇怪了,为什么别的 shell 命令执行时都是数据返回之后立马结束,而 bridge 命令会有明显的延迟?

好吧,让 Coding Agent 先看看,修复然后给我一个结论。

输入之后,我就去活动活动,舒展筋骨,喝了口水。

等我回到工位,我发现问题修复了。仔细一看,代码就改了一行,但总结却说了一大堆什么的,唯一让我印象深的是“事件循环”。

function waitForOpen () => { // 每 50ms 轮询一次 readyState const check = setInterval(() => { if (readyState === OPEN) { clearInterval(check); clearTimeout(timeout); // 修复后才有 resolve(); } }, 50); // 5 秒后认为连接失败 const timeout = setTimeout(() => { clearInterval(check); reject(new Error('Connection timeout')); }, 5000); } using client = new ManagedClient(options.server); // ← 块作用域开始 await client.waitForOpen();

我想着“这是啥?之前 python 项目里面似乎也有”看来这个概念是逃不掉的,得学~~

神秘的事件循环就是一个死循环

开始还以为是什么特别复杂的概念。一搜,发现这个的意思是在说执行代码的时候是单线程死循环,不停地执行任务队列中的任务。

拆成两部分就好理解了。事件指代的是待处理的任务(定时器、I/O、交互事件等等几乎所有方法调用都可以认为是事件),循环就是死循环~

或者,你把它理解为一个生产-消费者模型。事件循环指的就是用 while(true) 这样的方式不停地处理所有的消费者事件。

那回到刚刚的问题,这代码怎么就导致事件循环不能正常处理了呢?或者,为什么会延迟几秒呢?

// 每 50ms 轮询一次 readyState const check = setInterval(() => { if (readyState === OPEN) { clearInterval(check); clearTimeout(timeout); // 修复后才有 resolve(); } }, 50);

setInterval 里面在修复之前时没有 clearTimeout 的,所以主循环就会等待5s,超时之后才会继续执行,所以 Agent 跟我是事件循环导致有5s延迟,实际上是因为 setTimeout 泄露了。

这 Agent 把这理解的高度整的也太高了,直接整到了底层线程执行模型了!

但这,气氛都烘到这儿了,我突然又开始好奇了。为什么 Java 可以多线程执行?我在 JavaScript 和 Python 中能看到这样的语法,但底层都是事件循环,并不是多并发?

点击链接查看和 Kimi 的对话 Kimi | 循环Reactor

有兴趣的看看我和Kimi的对话,这里我简短点儿讲就是因为动态类型的语言,动态语言没法确定内存里面每个引用其后对象的大小。因为这一秒这个对象是 int,下一秒变 dict,内存不能预测,这导致无法做精确的逃逸分析、锁省略、无锁数据结构——编译器不知道指针会逃向何方,所以,只能放弃多线程。

难道经常说后端不能使用动态类型的语言是因为这个性能问题?

单纯从事件循环的CPU利用效率来看,其实它是高于多线程的。为什么很少人拿它做一些大规模的后端(基础设施)服务?

关键问题我觉得有两个。

一是响应不稳定。遇到高并发之后,如果某任务中需要使用较多的CPU,那后续任务就会被阻塞。

二是硬件资源浪费。现在的CPU都是多核,如果一个64核的CPU只能用一个核,那这相当于在花钱打水漂。

那为什么又适合前端呢?

我能想到的一种合理的解释就是,DOM并发操作的问题。最初的设计者也许是发现并发操作(渲染)DOM会有大量的锁冲突,还不如单线程提升对单核CPU的利用率。

--附录

点击链接查看和 Kimi 的对话 Kimi | 循环Reactor

Browser-Bridge: https://github.com/dkisser/browser-bridge

http://www.gsyq.cn/news/1588519.html

相关文章:

  • AutoCAD 2027
  • Variance in Adversarial Attack for Customized Diffusion Models
  • 2026参观游学考察(标杆企业商务游学考察详细版)
  • AI沙箱代理实战:用Modal实现安全可控的代码操作
  • Netflix推荐系统背后的用户体验工程实践
  • 3D医学影像AI实战指南:模型选型、数据适配与临床落地
  • TVA在物流分拣领域的独特价值(5)
  • 终极指南:如何在Windows系统上完全掌控LG Ultrafine显示器亮度
  • 大模型代理网络中的语义传播风险与防御实践
  • 基于 OpenSpec 实现规范驱动开发
  • Software 3.0实战指南:从自然语言编程到AI协同开发范式
  • 分享2026年6月gespC++一级模拟题
  • 小团队标配Litera Lito,大文件审校不再头大
  • 我用 FamilyPro 开通 ChatGPT 后,省下了一大笔订阅费
  • DeepChecks自动化验证:构建可落地的ML模型质量门禁
  • ArcObjects SDK 10.8完全指南:从零到精通的GIS开发实战教程
  • Kimi K2.5实测:长文本解析与中文语义理解能力深度评测
  • 投影投影接口定义
  • 【2013-10-17】Android应用开发笔记:自定义控件实现LCD显示
  • 大模型和搜索引擎到底有什么不一样
  • 药品追溯码扫码设备怎么选?医药全场景读码硬件技术选型分析
  • 【原创保姆级】OpenAI Codex 全平台安装配置教程(Windows/Mac)避坑完整版
  • 虚拟助手化技术对话管理系统与多轮对话设计
  • 后端别再卷CRUD了,强烈建议直接转Agent开发
  • 3步轻松搞定知网文献批量下载:告别繁琐手动操作的高效方案
  • 面向 IVD 医疗设备精密液体输送的运动物理量反馈速度补偿控制技术研究与工程实现
  • 【IDEA安装黑盒解密】:基于JetBrains官方源码级文档(v2024.1.3 Build #IU-241.14494.242)还原安装流程与签名验证机制
  • AI危险自信的本质与四步事实校验法
  • 终极网盘下载加速指南:LinkSwift直链助手让文件传输飞起来
  • 从大偏差原理到玻色气体自由能:环路与交织图像解析