判据要用真值而非代理
# 判据要用真值而非代理
你反复踩的坑不是「判断写错了」,而是判断用的那个量根本不是你要问的东西。 「第几次事件」「滚了多远」「动画转到第几帧」「这次会话缓存过没有」—— 它们都只是真值的代理,在边界条件下会和真值分叉,而且不报错。 解法统一:把判据换成真值本身(内容是否变化、元素是否可见、真实进度、真实加载状态)。
六处证据:每一处都是「用代理当判据」
| 出处 | 代理(错的判据) | 真值(对的判据) | 分叉后的症状 |
|---|---|---|---|
| 首次内容事件不能无条件跳过 | 事件序号(第 1 次就跳过) | 内容是否仍等于初始内容 | 空正文第一次粘贴图片被整个丢掉 → 保存不了 |
| 显示阈值应按元素可见性而非固定像素 | 固定滚动距离(scrollTop > 18) | 标题元素是否已滚出覆盖区 | 字号/行高不同 → 标题提前或延后出现 |
| 进度条要由真实进度驱动 | 无限循环动画 / 帧间隔计时 | 真实加载状态或经过时间 | 条件永不成立 → 进度条卡在假进度上 |
| 图片加载失败要可重试并升级到HTTPS | 「这场会话加载失败过」的缓存标记 | 本次请求的实际结果 | 一次失败被会话级永久记住 → 整场不再重试 |
| 缓存命中率 | 命中率数字(0 就以为坏了) | 「是不是每次都是新会话首请求」 | 测量动作本身绕过了被测对象 → 误判实现有 bug |
| 编辑器显示不能脱离真实光标状态 | 固定的渲染规则 / 滞后的 selection | 真实光标位置 | 源码与渲染同时出现;「看起来正常」但输入落到错误位置 |
综合判断
-
代理量在「典型输入」下与真值一致,只在边界处分叉。 这正是它们难被发现的原因: 日常使用完全正常,只在「第一次」「刚好滚动到临界」「刚好那一次失败」时出错 —— 所以第一反应永远是「偶发」,而不是「判据错了」。
-
代理量往往比真值更「好拿」,所以会被顺手用上:事件序号比内容比较便宜, 固定像素比测量元素位置便宜,循环动画比接真实进度便宜。省下的那点成本, 全部以「静默错误」的形式还回来。
-
可迁移的动作:写下任何一个条件判断时,追问一句 —— 「这个量和我真正要问的东西,在所有情况下都等价吗?」 只要答案不是「是」,就换成真值:内容比较、元素可见性、真实状态、显式记录。 配套:真值若不可得,就显式记录它(对照 更新时序要由本地最新状态决定)。
与既有 synthesis 的关系
- 更新时序要由本地最新状态决定 —— 讲时序上不能拿「最后发生的」冒充「最新的」; 本条更宽:讲判据本身不能拿代理量冒充真值。时序是「用环境状态当时间」的特例。
- 对照才产生信息 —— 代理量的问题正是「没造对照」:没拿真值对照,就看不出分叉。
- 分层要落到运行时才有效 —— 同源:约束/判据不落到真实来源上,就等于不存在。
为什么这是 synthesis
单看每一页,都是某个功能的一个具体 bug(粘贴丢图、标题时机、进度条、图片重试、缓存命中、光标显示)。 并排之后才看得出它们共享同一个失败形状:用可得的代理量代替了要问的真值。 这个形状与框架、业务无关,可以直接带走。
相关
- 首次内容事件不能无条件跳过 / 显示阈值应按元素可见性而非固定像素 / 进度条要由真实进度驱动
- 图片加载失败要可重试并升级到HTTPS / 缓存命中率 / 编辑器显示不能脱离真实光标状态
- 更新时序要由本地最新状态决定
- 对照才产生信息