jscope数据刷新机制深度解构:为什么你的波形总在“卡顿”?
你有没有遇到过这样的场景:
- 电机启动瞬间的电流尖峰,在波形上只闪了一下就消失,像被浏览器悄悄吃掉了;
- 多通道ADC数据明明是同步采集的,画出来却错开了一格时间,游标对不准;
- 切换到timebase = 1ms/div后,波形突然开始跳变、撕裂,甚至浏览器标签页直接无响应……
这些问题,和jscope本身无关,也和你的MCU采样率无关。它们几乎全部源于一个被严重低估的事实:你正在用“轮询重绘”的直觉,去驱动一个为实时流而生的双模调度引擎。
jscope不是传统示波器前端的简化版,它是一套运行在浏览器沙箱里的微型实时操作系统——没有线程、没有中断、没有DMA,只有requestAnimationFrame、环形缓冲区和精妙的时间仲裁逻辑。今天我们就彻底拆开它,不讲API怎么调,只说数据从串口进来,到像素点亮之间,到底发生了什么。
它不画图,它调度时间
先破除一个根本误解:jscope本身不采集数据,也不生成波形。它只是一个高度敏感的“数据守门人”——只做三件事:
- 收数据:把外部塞进来的
[ {t:123.45, v:2.34}, ... ]塞进环形缓冲区; - 算窗口:根据当前时间、
timebase和屏幕宽度,决定“此刻该画哪一段”; - 喂像素:把那一段数据,用抗混叠算法压缩成刚好填满Canvas宽度的点阵,交给渲染管线。
所以,所谓“刷新”,本质是一次时间窗口计算 + 一次缓冲区裁剪 + 一次增量绘制。而触发这整套动作的开关,有两个,且永远在博弈:
- ✅事件驱动—— “有新数据了,立刻画!”(快,但可能太碎)
- ✅时间驱动—— “不管有没有新数据,每33ms画一次!”(稳,但可能滞后)
它们不是并列选项,而是分层协作的主从关系:事件驱动负责抢跑,时间驱动负责兜底与校准。
时间驱动:那个你设了却没真懂的refreshInterval
你肯定写过这行配置:
refreshInterval: 33但你知道吗?这个数字