使用方法
- 先填四个参数:训练时长 30 秒、休息时长 15 秒、轮数 8、准备倒计时 5 秒,这就是页面打开时的默认方案,摘要区显示「全程 5:50、16 段」。
- 两个勾选项按需要留:勾上「结束后保留末轮休息」会多做一段休息;勾上「段间提示音」才会在切换和倒数 3 秒时发声,浏览器策略要求先在这页上点过一下才允许播放声音。
- 点「开始训练」。先是 5 秒准备倒计时,接着进入第 1 轮 30 秒训练;训练段结束时提示音变高、阶段标签切成「休息」,休息段结束时提示音变低、回到「训练」。
- 大号数字是当前这一段的剩余整秒,下方细条是全程进度,两个数字一起看:前者告诉你这一段还剩多久,后者告诉你整套还剩多少。
- 想中途停一下,点同一个按钮(文字会变成「继续」);点「重置」回到待开始状态;点「载入示例」恢复默认方案。参数改动不会打断正在跑的计时,只有点「重置」或重新开始才会按新参数重建。
这个 HIIT间隔训练计时器能解决什么问题
一是把「训练 30 秒、休息 15 秒、做 8 轮」从记忆里搬到屏幕上。HIIT 的强度全靠时间比撑着,靠心里默数容易出现一个致命偏差:训练段越数越短、休息段越数越长,最终训练量比计划低两三成。计时器把每一段都钉死在秒上。
二是不用一直盯着屏幕。动作做到位的时候人是没法看表的,所以在倒数 3 秒和段间切换放提示音,靠耳朵就能跟上节奏;提示音关掉之后画面依然会变色和翻数字,戴耳机不方便的场合也能用。
三是对比不同间歇方案的实际总量。同样是「做 8 轮」,2:1 的 30/15 和 1:2 的 20/40 在总训练时间上差了一倍多。正文里的对照表把 16 组常见方案的训练总时长、休息总时长和全程时长都算好,排课时不用再手算。
四是让 Tabata 这类固定方案还原准确。经典 Tabata 是 20 秒全力、10 秒休息、重复 8 轮,合计 4 分钟,其中包含最后一轮之后的休息。本工具默认跳过末轮休息,所以直接填 20/10/8 会得到 3 分 50 秒,差的那 10 秒正好是一个休息段——勾上「结束后保留末轮休息」就与原始口径一致。
本页不做这些事:不喊动作口令、不统计次数与重量、不保存训练历史、不做心率区间提示。要记录每天练没练,用页面底部的「习惯打卡」;要看某段时间花在哪,用「时间追踪器」。
分段计时原理:链式截止时刻、单调时钟与振荡器提示音
计时内核只有一行读数:performance.now()。它按 W3C High Resolution Time Level 2 规范返回单调递增的毫秒浮点数,只会往前走,遇到系统对时也不会跳。常见的替代写法是把阶段时长累加进一个计数器,每 100 毫秒加一次,这种写法在页面被切到后台时会出错——浏览器会把后台标签页的定时器节流到最快 1000 毫秒一次,30 秒的训练段能被拉成好几分钟。
关键设计是「链式截止时刻」。每一段不是记「已经跑了多久」,而是记一个绝对的截止时间戳:第一段截止在 start + 准备秒数,第二段截止在第一段截止 + 训练秒数,依次往后推。每一帧只做一次比较,now >= 截止时刻 就切段。这样即使某一帧因为卡顿晚了 200 毫秒才切,下一段的截止时间仍然从前一段的原定时刻往后排,整场 350 秒不会因为几十次小延迟累积成 355 秒。若写成「切段时以当前时间为新起点」,每次切换都会把该帧的误差吃进总时长,8 轮下来能多出好几秒。
刷新用 requestAnimationFrame,目的不是省电,而是让计时与显示解耦。计时只依赖时间戳相减,和帧率无关;60 Hz 屏幕上每秒检查 60 次,120 Hz 屏幕上检查 120 次,结果一样。剩余秒数用 Math.ceil 向上取整:剩 0.2 秒时显示 1 而不是 0,避免数字在阶段真正结束前就归零。
提示音来自 Web Audio 的振荡器。每次发声都现场建一个 OscillatorNode(正弦波)和一个 GainNode,增益包络在前 5 毫秒线性升到 0.18、在段尾线性降回 0,两端都做了斜坡,所以听不到「咔」的开头爆音。三个阶段用三个频率区分:训练开始 880 Hz(A5)、休息开始 440 Hz(A4)、倒数 3 秒短哔 660 Hz,频率遵循十二平均律,880 恰好是 440 的两倍频。注意 AudioContext 必须在用户操作之后创建或 resume(),这是浏览器的自动播放策略要求的,所以这个 HIIT间隔训练计时器把音频上下文的创建放在「开始训练」和「试听提示音」的点击处理里。
参数为什么取这些默认值。训练 30 秒、休息 15 秒是 2:1 的常见配比,既有足够强度又留出不完全恢复的间隙;轮数 8 与 Tabata 的原始设计一致,一轮 45 秒、8 轮约 6 分钟,普通人能完整做完。准备倒计时给 5 秒是留出放下手机、站好位置的时间,不需要可以填 0。休息时长允许填 0,此时训练段首尾相接,变成一组连续训练。
完整示例(数值仅作演示)
下面用页面打开时的默认值在这个 HIIT间隔训练计时器里跑一遍。示例条件与默认值完全一致:准备 5 秒、训练 30 秒、休息 15 秒、8 轮、跳过末轮休息。按链式截止时刻铺开的阶段序列是:
- 全程时长 = 5 + 8 × 30 + 7 × 15 = 350 秒,显示 5:50;
- 训练合计 = 8 × 30 = 240 秒(4:00),休息合计 = 7 × 15 = 105 秒(1:45);
- 有效训练占比 = 240 ÷ 350 = 68.6%,其余 31.4% 是准备与休息;
- 阶段总数 = 1 段准备 + 8 段训练 + 7 段休息 = 16 段,最后一段是第 8 轮的 30 秒训练,做完直接结束;
- 第 1 轮的 30 秒训练里,剩余秒数依次显示 30、29……1,在第 3、2、1 秒各响一次 660 Hz 短哔,随后 880 Hz 长音切到休息。
把同一组参数改成经典 Tabata(准备 0、训练 20、休息 10、8 轮),跳过末轮休息是 0 + 160 + 70 = 230 秒(3:50);勾上「结束后保留末轮休息」变成 0 + 160 + 80 = 240 秒(4:00),与 1996 年 Tabata 研究里的原始方案完全对上。两者只差一个休息段的 10 秒,也正是最容易被人忽略的地方。
常见间歇方案与总时长对照表
下表按「跳过末轮休息」的口径逐个算出 16 组常用方案的总量,准备时间一律按 5 秒计(Tabata 两行按原始口径取 0 秒)。表里所有数字都由页面里的复算脚本按 准备 + 轮数 × 训练 + (轮数 − 1) × 休息 算出,可以直接拿去排课。
| 方案 | 训练 / 休息 | 轮数 | 训练合计 | 休息合计 | 全程 |
|---|---|---|---|---|---|
| Tabata 经典 | 20 / 10 | 8 | 2:40 | 1:10 | 3:50 |
| Tabata 含末轮 | 20 / 10 | 8 | 2:40 | 1:20 | 4:00 |
| 默认 HIIT | 30 / 15 | 8 | 4:00 | 1:45 | 5:50 |
| 30 / 30 × 10 | 30 / 30 | 10 | 5:00 | 4:30 | 9:35 |
| 40 / 20 × 8 | 40 / 20 | 8 | 5:20 | 2:20 | 7:45 |
| 45 / 15 × 10 | 45 / 15 | 10 | 7:30 | 2:15 | 9:50 |
| 20 / 40 × 6 | 20 / 40 | 6 | 2:00 | 3:20 | 5:25 |
| 60 / 60 × 5 | 60 / 60 | 5 | 5:00 | 4:00 | 9:05 |
| 30 / 90 × 6 | 30 / 90 | 6 | 3:00 | 7:30 | 10:35 |
| 15 / 15 × 12 | 15 / 15 | 12 | 3:00 | 2:45 | 5:50 |
| 50 / 10 × 10 | 50 / 10 | 10 | 8:20 | 1:30 | 9:55 |
| 30 / 30 × 8 | 30 / 30 | 8 | 4:00 | 3:30 | 7:35 |
| 25 / 5 × 12 | 25 / 5 | 12 | 5:00 | 0:55 | 6:00 |
| 30 / 20 × 10 | 30 / 20 | 10 | 5:00 | 3:00 | 8:05 |
| 60 / 30 × 8 | 60 / 30 | 8 | 8:00 | 3:30 | 11:35 |
| 20 / 20 × 15 | 20 / 20 | 15 | 5:00 | 4:40 | 9:45 |
挑方案时先看训练合计而不是轮数:同样是 8 轮,20/10 只有 2 分 40 秒的工作量,40/20 有 5 分 20 秒;再看休息合计,20/40 的休息时间比训练时间还长,这一组实际更接近低强度的间歇恢复,适合刚开始接触间歇训练的人。
输入范围、边界与舍入
- 准备倒计时 0~60 的整数秒。填 0 表示点下「开始训练」直接进入第一轮训练,不做倒数。
- 训练时长 5~600 的整数秒。下限 5 秒是因为再短的训练段连一次完整动作都做不完,计时器会一直在切段;上限 600 秒,超过就属于持续性训练,用普通秒表更合适。
- 休息时长 0~600 的整数秒。填 0 时休息段会被整段跳过,训练段首尾相接,阶段数从 16 变成 9(1 段准备 + 8 段训练)。
- 轮数 1~99 的整数。轮数 1 且休息非 0 时,因为末轮休息默认跳过,实际不会出现任何休息段。
- 理论上限约 33 小时。按准备 60 秒、训练 600 秒、休息 600 秒、99 轮、含末轮休息算,全程 118860 秒 ≈ 33.02 小时,这个数字只是参数范围相乘的结果,不是推荐值;实际使用超过 1 小时的方案建议改用系统闹钟。
- 剩余秒数向上取整。剩余 30.0 到 29.1 秒都显示 30,显示 1 之后才切段,所以数字不会提前归零,也不会出现 0。全程时长在摘要区用
m:ss显示,取整到秒。 - 页面切到后台不会把时长算歪。
requestAnimationFrame在后台会暂停,但截止时刻是绝对时间戳,切回来的第一帧读到真实经过时间后,会一次性跳过所有已经过期的阶段,直接落到当前该在的那一段。代价是中间错过的提示音不会补发,切回来的瞬间可能只响当前这一段的音。 - 声音需要一次用户操作才允许播放。这是浏览器的自动播放策略:
AudioContext在没有任何点击的页面上会处于suspended状态,发不出声。本工具把音频上下文的创建放在「开始训练」「试听提示音」的点击处理里,只要点过其中任意一个就正常。关掉「段间提示音」只是不再发声,画面照常切换。
常见问题
为什么不用 setInterval 每秒减一?
因为定时器会被浏览器节流。页面切到后台后,后台标签页的 setInterval 最小间隔会被抬到 1000 毫秒,一串「每秒减一」的累加会越减越慢,30 秒的训练段可能被拉成好几分钟;而按 performance.now() 的绝对截止时刻判断,无论中间漏了多少次检查,时间一到就切段。这也是这个 HIIT间隔训练计时器把计时和刷新彻底分开的原因。
点开始之后没有声音,是怎么回事?
多半是自动播放策略拦下了。浏览器要求页面在用户手势之后才允许播放音频,如果只是刷新页面、没有点击过任何按钮就调用了播放接口,音频上下文会停在 suspended 状态。解决办法就是点一下「试听提示音」或「开始训练」,有了一次真实点击之后声音就正常了。另外手机静音开关、浏览器标签页被静音也会导致无声。
训练到一半切去看别的页面,回来时间还准吗?
时间准,声音不一定。截止时刻记的是绝对时间戳,切回来时工具读一次 performance.now(),把已经过期的阶段一次性跳过,直接落到当前应该在的那一段,总时长不会因为后台暂停而变长。但后台期间 rAF 不运行,那些本该响的提示音不会补发,所以可能出现「切回来发现已经到第 4 轮休息了」的情况,建议练的时候让页面保持在前台。
最后一轮训练完为什么直接结束了,不再休息一次?
这是默认行为,可以用勾选框改。训练结束后紧接着进入休息,练完又不会再做一组,那段休息对训练本身没有意义,跳过可以让整套流程干净收尾。经典 Tabata 的原始方案口径是包含末轮休息的 4 分钟(8 × (20 + 10) = 240 秒),本工具默认跳过末轮得到 3 分 50 秒,想完全对齐就勾上「结束后保留末轮休息」。
三种提示音分别代表什么?
训练开始是 880 Hz 的较高音,休息开始是 440 Hz 的较低音,倒数 3 秒各有一次 660 Hz 的短哔,全部完成时是三声连续的高音。频率都取自十二平均律,880 是 440 的两倍频,两个音听起来是同一个音名的不同八度,容易分辨;每段声音的开头和结尾都加了 5 毫秒的增益斜坡,避免出现爆音。
休息时长填 0 会怎样?
休息段会被整段跳过,训练段首尾相接,等于连续做指定轮数。摘要区的「休息合计」会显示 0:00,「阶段数」也会相应减少——8 轮、准备 5 秒的方案会从 16 段变成 9 段。这种用法适合本来就不需要间歇的动作,或者想先用连续训练摸一次底再切回间歇节奏。
改参数会打断正在跑的计时吗?
不会。阶段序列在点「开始训练」的那一刻就已经按当时的参数固定下来,中途改输入框只刷新下方的方案摘要,正在跑的这组不受影响。想让新参数生效,点「重置」之后再点「开始训练」。这样做是为了避免练到第 5 轮被改动打乱节奏,也避免出现「轮数改成 3,但已经跑到第 6 轮」的错乱。
方案会被保存下来吗?关掉页面会不会丢?
不会保存。参数只存在当前页面的输入框里,刷新或关闭就回到默认的 5 / 30 / 15 / 8。这是刻意的:本页不写浏览器存储,也不发任何网络请求,所以同一台电脑上不会留下训练记录,也不会影响别人打开这个页面时看到的默认值。常用方案建议直接写在纸上或手机备忘里,照着填一遍很快。