第七章:性能开始说话

0 阅读4分钟

问题不是突然出现的。

它更像是某个凌晨三点的警告灯,

不是刺耳地响,而是安静地亮了一下。

最先注意到的是测试同事。

“阅读器在长章节下,滚动有点卡。”

这句话被丢进群里的时候,没有加感叹号,也没有截图。

太普通了。

林晨却在看到的那一刻,心里轻轻沉了一下。


他打开测试环境,加载了一本内部用来压测的书。

章节很长,

没有花哨格式,

只是纯文本。

滚轮向下。

前两屏,很顺。

第三屏开始,有一点迟滞。

不是掉帧,是那种你说不清楚,但手能感觉到的慢

林晨停下滚动,打开 DevTools。

不是 Network,

是 Performance。


他点下 Record。

滚动。

停止。

一条时间线慢慢铺开。

紫色的 scripting,

绿色的 rendering,

黄色的 painting。

没有哪一段“炸掉”,

但每一段,都比他预期的多了一点。

“嗯……”

他把 timeline 放大。


罪魁祸首并不复杂。

watch(
  () => readingSettings.value,
  () => {
    recalcReadingStyle()
  },
  { deep: true }
)

deep watch。

他盯着这段代码看了几秒,没骂自己。

这是一个当时看来很合理的选择

设置项集中在一个对象里,

深度监听,

统一响应。

逻辑很干净。

代价,是每一次滚动时的连锁反应


滚动本身不改设置。

但滚动会触发进度更新。

进度更新,会触发依赖。

依赖里,

藏着一次 style 重新计算。

浏览器不会告诉你:

“你不该这样写。”

它只会慢慢地,

开始喘。


林晨没有立刻修。

他先做了一件事——

写下结论。

不是 bug,是结构性损耗。****


下午的评审会上,

他没有直接放 Performance 面板。

他先问了一个问题。

“你们在用阅读器的时候,

有没有觉得哪一刻开始不顺?”

苏雨想了想。

“翻页还好,

就是读久了,会有点累。”

这不是心理问题。

这是帧率。


林晨这才把时间线投出来。

“现在的架构下,”

他说,“我们把阅读设置阅读行为耦合在了一起。”

“用户滚动,本该只是浏览器的事,

但现在,每一次滚动,

都会经过我们的响应系统。”


他在白板上写:

滚动
 ↓
进度更新
 ↓
watch 触发
 ↓
样式重算
 ↓
DOM diff

“链条不长,”

他说,“但它一直在跑。”


张明皱眉:“那为什么之前没问题?”

林晨没有马上回答。

他等了一秒。

“因为之前,

我们还没把系统逼到边界。”

“测试数据少,

阅读时间短,

用户行为简单。”

“现在不是代码变差了,

是使用方式变真实了。”


苏雨没有插话。

她只是看着那条链。

“能优化吗?”

她问。

“能。”

林晨点头。

“但不是补丁。”


他切到另一页。

const readingStyle = computed(() => {
  // 只依赖设置
})

“第一步,

把所有与滚动无关的东西,

从响应链里拆出去。”

“第二步,

进度更新只记录数值,

不触发 UI 级别的响应。”

“第三步,”

他停了一下,“限制响应系统的‘影响范围’。”


这不是一行代码。

这是一次思想上的收紧


会后,苏雨留下来。

“所以,”她说,“我们现在的感觉,其实是系统在提醒我们。”

“对。”

林晨点头。

“它没崩,

但它在告诉你:

我不能再随便被用了。”


那天晚上,林晨改得很慢。

他没有一口气重构完。

每拆一个依赖,

他就重新跑一次 Performance。

不是为了指标,

而是为了确认——

系统有没有更安静一点。****


凌晨一点。

滚动。

时间线变短了。

紫色少了,

绿色也收敛了。

不是完美,

但顺了。


他在 commit message 里写了一句话:

decouple reading behavior from style reactivity

没有人会在意这句话。

但他知道,这是一次转向。


第二天早上,苏雨在群里发了一条测试反馈:

滚动顺多了。

那种“读久了会累”的感觉没了。

林晨看着这句话,没有笑。

他只是关掉群聊,继续写代码。

他心里很清楚——

真正复杂的系统,不会靠一次优化就安全。****

但至少现在,

他们听懂了性能在说什么。