功能价格文档博客
获取 mote
← 博客
工程·2026年6月20日·阅读需 4 分钟

笨重的根源不是 Markdown,而是 Web 引擎

仅仅打开 Markdown 编辑器风扇就开始转,并不是因为 Markdown 的开销高。在相同条件下对同一篇文档进行测量,就会发现成本来自渲染引擎和与时钟绑定的循环。

m
mote
在同一个 Xvfb 中测得的两个应用处理同一份 7.5 KB 文档时的空闲 CPU 和内存占用。上方较短的条形代表没有 Web 引擎的原型。
在同一个 Xvfb 中测得的两个应用处理同一份 7.5 KB 文档时的空闲 CPU 和内存占用。上方较短的条形代表没有 Web 引擎的原型。

我在笔记本电脑上打开了 Markdown 编辑器。什么都没有输入,风扇却开始转了。

一开始,我以为是 Markdown 导致的。我以为是因为不断重新绘制文档才变慢的。

真的是这样吗?

我在相同条件下进行了比较

我将屏幕尺寸、渲染方式和文档全部设为相同。打开一份 7.5KB、113 行的文档,然后在 25 秒内什么都不做。输入时,也以相同的速度输入相同的文字。

使用 Web 引擎绘制预览的 apostrophe,空闲 CPU 使用率为 34.6%,内存占用为 378MB。进程有 5 个。

不使用 Web 引擎、以内联方式绘制同一份文档的原型,CPU 使用率为 0.7%,内存占用为 64MB。进程只有一个。

两者都在绘制 Markdown,但结果相差很大。

在 apostrophe 中仅关闭预览后,CPU 使用率降至 7.0%,内存占用降至 133MB。应用和工具包都没有改变。改变的只有绘制预览的方式。

我还测量了完全不绘制 Markdown 的文本编辑器。CPU 使用率为 2.2%,内存占用为 79MB。

绘制 Markdown 的原型反而更轻量。

这时我才确定。问题并不在 Markdown。

即使什么都不做,它每秒也在工作 60 次

原因出在让预览滚动与正文保持同步的代码上。

这段代码并不是只在滚动时运行。每隔 16ms,定时器就会唤醒,并在 WebKit 进程中执行 JavaScript。收到响应后,又会重新设置定时器。

即使没有人操作窗口,它每秒也会工作大约 60 次。

使用 Web 引擎后,编辑文档的区域和绘制预览的区域会变成两个不同的世界。让两边状态保持一致,最简单的办法就是不断检查。如果不单独测量空闲 CPU,这项开销很难被发现。

输入时,差距变得更大。apostrophe 的 CPU 使用率为 180%,原型则为 41%。

一边每次按键都要经过浏览器进程。另一边只为发生变化的行重新添加标签。

我把测量结果变成了设计原则

这个原型并没有采用什么特别的优化。

样式通过标签应用在文本上。多次编辑会被汇集到一个会自行消失的一次性 idle 中。重新添加标签的范围被限制在发生变化的行。进程也只使用一个。

这并不是增加了什么,而是没有放入不需要的东西。

此后,我制定了两条设计原则。

第一,不把 Web 引擎加入依赖项。

第二,如果文档没有变化,也没有动画,就不安排帧、定时器或 tick。

这些原则很难在后期补上。Web 引擎不只是一个简单的库,它会改变应用的结构。一旦加入,移除它就等同于重新开发。定时器也是如此,如果没有规则,每增加一个功能就会多出一个定时器。

作为代价,我不得不放弃简单的做法。无法通过轮询检查文件变更,也不能把公式交给 WebView 处理。所需的布局必须自己实现。

为了避免这些原则逐渐变得模糊,每次发布时,我都会在真实设备上重新测量。

在真实 GPU 上运行的性能门禁输出。窗口出现后,空闲状态下绘制的帧数为 0,CPU 使用率为 0.10%。
在真实 GPU 上运行的性能门禁输出。窗口出现后,空闲状态下绘制的帧数为 0,CPU 使用率为 0.10%。

查看数字时也有需要注意的地方

实验采用软件渲染进行。CPU 使用率会比真实 GPU 环境下更高。因此,与其看绝对值,更应该看比例。

原型空闲时 0.7% 的 CPU 使用率也大多来自光标闪烁。关闭闪烁后,几乎无法将它与 0 区分开来。

这并不意味着所有基于 Web 引擎的应用都会遇到相同的问题。这次的结果仅限于 apostrophe。也有像 Chromium 系列那样会在空闲状态下减少工作的引擎。

原型的功能也不多。它没有表格、公式、导出和查找功能。能够比较的仅限于渲染成本。

即便如此,有一点是明确的。

产生成本的并不是 Markdown,而是渲染引擎和永不停歇的循环。

只要准确找到原因,轻量化就不再是一项新功能,而会变成减法。

← 较早再做一款 Markdown 编辑器的理由较新 →即使切换模式,文档仍是同一份
通过RSS持续关注。
只留下文字
简体中文
© 2026 mote