我做了一个反应力测试,后来发现最难的根本不是计时
最开始我只是想做一个很简单的反应力测试。
规则简单到几乎不需要说明:等屏幕发生变化,然后尽快点击,最后计算从信号出现到点击之间经过了多少毫秒。
从代码上看,这件事甚至有点过于简单。
const start = performance.now();
// 用户点击以后
const reactionTime = performance.now() - start;
我原本以为做到这里,这个页面差不多就结束了。
但自己连续测了几十次以后,我发现真正麻烦的问题才刚刚开始。同一个人,上一轮可能是 218ms,下一轮是 191ms,再下一轮又变成 236ms。偶尔还会蹦出来一个快得连自己都不太相信的数字。
于是我开始想一个看起来很简单的问题:
到底哪一个数字,才算“我的反应速度”?
计时不难,测试流程才是第一个坑
真正开始把页面当成一个可以反复使用的测试,而不只是 Demo 以后,最先冒出来的是各种状态问题。
用户还没等到信号就点了怎么办?结果出现以后再次点击是重新开始,还是应该忽略?鼠标、触屏、空格键和 Enter 要不要走同一套流程?连续测试五轮的时候,上一轮什么时候结束,下一轮又应该什么时候开始?
后来我干脆把整个过程当成一个很小的状态机来看。
准备
↓
等待随机时间
↓
信号出现
↓
等待用户反应
↓
记录成绩
↓
显示结果
而提前点击实际上是另一条分支:
等待信号
│
├── 用户提前操作 → Too Soon
│
└── 信号出现 → 正常计时
这些逻辑单独看都不复杂,但它们决定了一个测试玩起来到底像不像一个完整的东西。
我后来越来越觉得,小工具里真正花时间的地方,经常不是最核心的那几行代码,而是这些“正常情况下不会注意,出问题时马上就能感觉到”的细节。
一次最好成绩,其实没有我想象中那么有意义
第一版只显示单次成绩。
比如:
Reaction Time
183 ms
看起来很干净,也很容易理解。
但连续测试之后,我开始不太喜欢这种表达。
因为 183ms 有可能只是十几次里面偶然出现的一次。如果其他几次分别是 214ms、207ms、225ms 和 219ms,只留下那个最好看的数字,很容易让人误以为自己的正常反应就是 183ms。
所以后来我给反应力测试增加了单次和多轮两种玩法。想随手测一下,可以只测一次;想认真一点,就连续测几轮,再看平均成绩、最快成绩以及几次之间的波动。
同样是一个数字,放进上下文以后感觉会完全不同。
最快 191 ms
平均 207 ms
最近:
203 / 218 / 191 / 214 / 209
这时候 191ms 仍然是一个很好的成绩,但它不再独自代表整个测试。
我觉得这样反而更诚实。
然后我开始给页面加一点“记忆”
做到这里以后,我又碰到了一个问题。
假设今天测出来是 205ms,关掉网页;三天以后重新回来,又测出了 194ms。如果页面已经把三天前发生的事情忘得干干净净,那么新的 194ms 其实少了一部分意义。
因为真正让我产生感觉的往往不是:
今天是 194ms。
而是:
等等,我上次是不是 205ms?
于是我开始把最近的一些成绩留在浏览器里。
为了保存这么一点数据,我没有马上去做注册、登录、用户表和服务器同步,而是先用了浏览器本地存储。对一个点开以后几秒钟就能开始的小测试来说,我觉得为了保存成绩强迫用户先注册,成本有点太高。
示意代码其实很普通:
const KEY = 'reaction-results';
function saveResult(score) {
const history = JSON.parse(
localStorage.getItem(KEY) || '[]'
);
history.unshift({
score,
createdAt: Date.now()
});
localStorage.setItem(
KEY,
JSON.stringify(history.slice(0, 20))
);
}
但这个小变化改变了整个页面的逻辑。
原来是:
测试 → 得到成绩 → 结束
后来变成:
测试 → 成绩 → 保存 → 比较 → 再测试
我现在回头看,觉得这里才是这个小项目真正开始变得有意思的地方。
浏览器测出来的 200ms,也不是一个脱离环境的数字
做反应测试久了以后,我还越来越不敢把结果说得太绝对。
同一个人在不同设备上测试,结果可能并不完全一样。鼠标和触屏不是同一种输入方式,显示设备、浏览器和系统本身也都会参与整个过程。
浏览器最终能够告诉我的,其实更接近:
你在当前设备和当前状态下,这一次记录到了 200ms。
而不是:
你这个人的反应能力就是 200ms。
这也是为什么我现在更倾向于让用户在相近的设备和环境下跟自己比较,而不是拿两个完全不同设备上的成绩直接横着比。
数字可以很精确,但解释数字的时候还是应该留一点余地。
做完反应以后,我开始试一些完全不同的东西
反应测试做了一段时间以后,我并没有特别想继续做第二个、第三个“换皮反应测试”。
我开始想:如果还是这种打开就能玩的形式,还有什么能力可以被拆成一个很简单的挑战?
于是有了序列记忆测试。
几个方块依次亮起来,用户记住顺序,然后自己重新点一遍。它让我觉得有意思的地方是,难度根本不需要突然跳级,只要每一轮比上一轮多一个步骤,人自然会在某个位置遇到自己的边界。
前几轮经常会觉得:
这有什么难的?
然后某一轮突然连刚才第三个亮的是哪块都想不起来了。
后来又做了数字记忆测试。它看起来和序列记忆很像,但自己玩的时候感觉完全不一样。数字短的时候几乎不用刻意记,长度增加以后,经常不是整串数字完全消失,而是中间某两个位置突然串掉。
同样叫“记忆”,实际要求人的方式可以完全不同。
瞄准训练又换了一个方向。
目标出现以后,需要发现目标、移动鼠标并完成点击。自己连续玩以后会很明显地感觉到,“眼睛已经发现了目标”和“手已经准确点到了目标”其实不是同一个动作。
尤其连续出现很多目标以后,有时候这一颗非常快,下一颗却突然慢下来;有时候移动得很快,但最后偏了一点。
这些细节如果只是看规则,其实很难感觉出来,真正自己点几十次以后才会暴露出来。
我最喜欢的一个,是规则只有三个字:别跟丢
后来我又做了多目标追踪测试。
开始时先告诉用户几个指定目标,然后所有物体一起移动。等移动结束以后,再把最开始的目标找出来。
它的规则从头到尾几乎没有变化:
别跟丢。
真正让难度发生变化的是移动速度、目标数量和轨迹。
尤其几个物体靠近、交叉、再分开的瞬间,很容易突然产生一种感觉:
我刚刚盯的到底是左边这个,还是右边这个?
明明一直觉得自己没有移开视线,最后选择的时候却发现早就不知道在哪一步跟错了。
最后还有斯特鲁普测试。
这个测试让我觉得好玩的地方恰好相反:规则已经知道得非常清楚,人还是会犯错。
比如文字写着“蓝色”,实际显示出来却是红色,要求按照实际颜色回答。
脑子知道应该忽略文字本身,但连续做起来以后,文字还是会很自然地干扰判断。
这时候我才越来越明显地感觉到:
知道一条规则,和能够稳定地执行这条规则,并不是完全一样的事情。
后来我才把这些测试放到了一起
做到这里的时候,我才开始把前面的东西当成同一个项目。
反应、瞄准、数字记忆、序列记忆、多目标追踪、斯特鲁普,看起来测的是不同东西,但产品结构其实越来越相似:
理解规则
↓
完成一次挑战
↓
得到结果
↓
留下记录
↓
和之前比较
↓
再试一次
后来我把它们整理成了一个人类基准测试小站。
但现在回头看,我觉得“有多少个测试”反而不是最重要的事情。
真正让我花时间思考的是:
一个用户完成一次测试以后,页面还能留下什么?
用户为什么要回来一次?
这可能是我做到现在觉得最难回答的问题。
增加一个新的测试并不难。
今天做数字记忆,明天可以继续做另一个小游戏。网站里的卡片会越来越多,看上去也会越来越“完整”。
但如果每个测试都是:
打开
↓
测一次
↓
得到一个数字
↓
关闭
那么无论有六个还是六十个,本质上都还是一次性体验。
所以我现在越来越在意的是另外一条链路:
测试
↓
成绩
↓
历史
↓
变化
↓
比较
↓
再测试
比如:
今天比昨天快了 12ms。
最近五次里这次最好。
上次只能记 8 位数字,这次到了 9 位。
这些东西并不需要额外写一篇文章才能产生。
用户自己在使用工具的过程中,就已经产生了内容。
成绩是内容,历史是内容,变化也是内容。
这也是我最近越来越喜欢的一种产品思路:
工具本身也可以成为内容。
我反而暂时不想急着加登录
按照常见的产品路线,下一步似乎很容易变成:
账号、排行榜、云同步、用户主页、成就系统……
这些当然都可以做。
但我现在还没有急着加。
因为我自己使用这种测试时最喜欢的一件事,就是点开以后马上能开始。
如果用户只是想看看今天反应快不快,却先看到:
注册账号
↓
填写邮箱
↓
验证
↓
登录
↓
终于开始测试
那这个工具已经变成了另一种东西。
现在我宁愿先接受本地存储的缺点:换设备不会同步,清理浏览器数据以后历史也会消失。
至少换来的东西是:
打开,就能玩。
对这种只有几分钟甚至几十秒使用时间的产品,我越来越觉得“少做一点”有时候也是一种设计。
最后
最开始我只是想知道:
我的反应到底有多快?
真正做进去以后,我遇到的问题慢慢变成了:
一次成绩到底意味着什么?
为什么同一个人每次测出来都不一样?
哪些记录值得留下?
用户为什么明天还会再回来一次?
这些问题并不是什么高深的技术难题,但它们让我对“小工具”这三个字有了一点不一样的理解。
一个页面可能只有一个按钮,一次使用可能只有十几秒,但真正做进去以后,计时、输入、状态、历史、设备差异、结果解释和重复使用,都会慢慢冒出来。
我现在反而挺喜欢这种项目。
问题很小,所以真的有机会把它做完;但只要继续往里面走一点,又总能发现下一个之前没有想过的问题。
而现在我最想继续解决的,也已经不是“下一个应该再做什么测试”。
而是:
怎样让下一次测试,比第一次更有意义。

本作品采用《CC 协议》,转载必须注明作者和本文链接
关于 LearnKu