给本地存储加一道恢复校验:专注时钟的9组边界检查
给小工具增加“刷新后恢复进度”,最直接的做法是把状态保存到 localStorage,再在页面启动时读取。但“能够解析成 JSON”和“能够作为应用状态使用”是两回事。
我在“节奏·专注时钟”中保存了模式、剩余时间、结束时间、运行状态和完成状态。今天围绕已有实现做了9组浏览器检查:合法状态能否恢复,损坏或不合理的数据能否退回初始状态,以及存储不可用时页面是否仍能运行。
先确定应用允许什么状态
这个工具有25分钟专注、5分钟短休息和15分钟长休息三种模式。恢复数据时,模式必须属于这三个选项;剩余时间必须是有限数值,且位于零和当前模式时长之间;运行与完成标记必须是真正的布尔值。
以下是从实际恢复逻辑中摘出的校验条件:
Object.hasOwn(durations, s.mode) &&
Number.isFinite(s.remaining) &&
s.remaining >= 0 &&
s.remaining <= durations[s.mode] &&
typeof s.running === 'boolean' &&
typeof s.completed === 'boolean'
这里检查的是允许范围,而不是数据看起来像不像。字符串 "false" 不是布尔值 false,负数不适合作为剩余时间,5分钟模式也不应恢复出超过5分钟的剩余时间。遇到不符合条件的数据,已有实现会保留默认的25分钟初始状态。
恢复时重新构造对象
校验通过后,代码只取应用需要的字段,重新构造状态对象:
state = {
mode: s.mode,
remaining: s.remaining,
deadline: s.running ? s.deadline : null,
running: s.running,
completed: s.completed
};
这种写法让恢复边界更清楚。暂停状态不需要继续携带旧的结束时间,额外字段也不会因为一次整体赋值进入当前状态。
运行中的状态还会检查结束时间是否为有限数值,并限制明显超出当前模式时长的未来时间。已经过去的结束时间则交给渲染逻辑处理:剩余时间归零,转为完成状态。这是本工具采用的恢复规则。
9组浏览器检查的结果
我用同一份实际HTML,在受控测试页面中逐项注入存储内容,并读取界面输出。结果如下:
| 输入或环境 | 预期与实际结果 |
|---|---|
| 合法的短休息暂停状态,剩余180000毫秒 | 显示03:00 |
| 无法解析的JSON | 回到25:00 |
| 未知模式 | 回到25:00 |
| 剩余时间为负数 | 回到25:00 |
| 剩余时间超过当前模式时长 | 回到25:00 |
| 用字符串替代运行标记 | 回到25:00 |
| 已经过期的运行结束时间 | 显示00:00并结束本轮 |
| 读取存储时抛出异常 | 页面仍显示默认25:00 |
| 写入存储时抛出异常 | 点击开始后仍进入计时状态 |
这9组结果均符合预期。测试只覆盖表中场景,不能据此声称已经穷尽所有字段组合。
存储失败时保留基本交互
本工具把读取、解析和写入放在异常处理之内。这样,即使本次无法持久保存,用户仍能在当前页面开始、暂停和重置计时。
这种降级有明确代价:存储失败后,刷新恢复就没有保证。后续可以增加简短的状态提示,让用户知道进度仅在当前页面保留。当前版本尚未增加这项提示。
另一个后续改进点是字段之间的一致性。例如“正在运行”和“已经完成”同时为真时该如何处理,应当有单独的规则和对应测试。当前实现检查了字段类型和部分范围,但还不能把它称为完整的状态模型校验。
这次检查让我把恢复功能分成了三个可以分别验证的问题:输入能否解析、字段是否符合应用范围、恢复后界面是否表现正确。把这三个环节逐一检查,比只验证“刷新一次还能看到时间”更容易发现遗漏。
- 点赞
- 收藏
- 关注作者
评论(0)