倒计时器

设置小时、分钟、秒,或者直接指定一个目标时刻;剩余时间按「目标时刻减当前时间」重算,后台标签页被浏览器节流、回到前台后会自动校正。

00:05:00
未开始 · 点「开始」后按 Date.now() 记录目标时刻。
剩余00:05:00
目标时刻(本地)—
目标时刻(UTC)—
定时器触发0 次
尚未开始:本页每次刷新都用「目标时刻减当前时间」重算,不做「每次加一秒」的累加。

提示:在任意输入框里按 Enter 可以直接开始或继续;打开页面时默认是 00:05:00,与下面「完整示例」和对照表用的是同一个值。

使用方法

  1. 页面打开时默认是「按持续时长」模式,时长框里是 0 时 5 分 0 秒,大字区显示 00:05:00,与下面「完整示例」和对照表是同一个值。
  2. 倒计时固定长度就在小时、分钟、秒三个框里填,也可以点「1 分钟 / 5 分钟 / 10 分钟 / 1 小时」快捷按钮。
  3. 盯着绝对时刻就把模式切到「按指定时刻」,只填 HH:MM(如 20:00):按本地时区解释,今天已过则自动算明天,并在提示里说明。
  4. 点「开始 / 继续」或在任意输入框按 Enter,目标时刻被记成绝对时间戳,结果卡同时显示本地与 UTC 时间;「暂停」冻结剩余,继续时按新的目标时刻重算。
  5. 诊断行会显示定时器触发次数与墙钟偏差。切到别的标签页时定时器被清掉,回到本页按当前时间重算再继续刷新,所以后台待多久都不会多走或少走。

这个倒计时器能解决什么问题

一是给固定时长掐表。煮咖啡、限时发言、热身拉伸要的是「从现在起 N 分钟」,默认 5 分钟档直接可用,快捷按钮覆盖 1 分钟到 1 小时。

二是盯着一个绝对时刻。会议 20:00 开始、车次 08:15 发车,要的不是「还有多久」而是「到某个定点」。本工具支持只填 HH:MM,把目标时刻记成时间戳,剩余量由它减当前时间得出。

三是长时间挂后台也不失准。浏览器会给后台标签页的定时器限速,很多网页倒计时因此越跑越慢;本工具不靠触发次数计秒,切回前台按当前时间重算,挂 8 小时和挂 5 分钟一样准。

四是把「为什么会越走越慢」讲清楚。诊断行实时显示触发次数与墙钟偏差,原理一节给出累加式的实测漂移表,两处对照就能理解为什么「每次加一秒」是错的。

本页不做这些事:不做从零开始正向累加(→在线计时器);不做分段计次与圈速(→在线秒表);不做「工作 25 分钟 + 休息 5 分钟」的循环(→番茄钟计时器);不做到点反复响铃(→闹钟);也不做「跑 30 秒歇 15 秒」的间歇循环(→间隔计时器HIIT)。

为什么「每次加一秒」会越走越慢:setInterval 漂移与绝对时间基准

这个倒计时器内部只有一个减法:remain = Math.max(0, toEnd - Date.now())。toEnd 是开始那一刻算出的绝对目标时间戳,之后每次刷新都用它减当前时间。常见的错误写法是反过来的:setInterval(function(){ left -= 1000 }, 1000),靠触发次数计秒。规范只保证 setInterval 的间隔不小于 1000 毫秒,回调排队、渲染、垃圾回收都会插在中间,设额外开销为 d 毫秒,真实周期就是 1000 + d,累加式在墙钟走过 T 毫秒后只触发 floor(T / (1000 + d)) 次。d 取 1 毫秒,1 小时后就慢 4 秒、8 小时慢 29 秒;d 取 5 毫秒则是 18 秒与 144 秒。绝对时间基准与触发次数无关,偏差恒为 0,唯一可感知的误差是 200 毫秒的显示刷新粒度,且不累积。

后台节流会把这笔账放大几十倍。按 Chrome 现行策略,标签页隐藏后 setInterval 最快也只能 1 秒一次,隐藏满 5 分钟进入 intensive throttling,最多 1 分钟一次。累加式因此断崖式欠账:隐藏 30 分钟只触发 325 次,显示成 00:05:25;隐藏 8 小时只触发 775 次,显示 00:12:55,而墙钟早已走完。绝对时间基准回到前台的第一次刷新就会修正。本页更省一步:页面一隐藏就调用 clearInterval,不在后台空转。可见性判据用 W3C Page Visibility 规范定义的 document.hidden 与 visibilitychange,比监听 window 的 blur / focus 可靠——切换应用、锁屏、最小化都会正确改变可见性;事件必须挂在 document 上,挂到 window 在部分浏览器收不到。

Date.now() 与 performance.now() 是两套时钟。前者返回自 1970-01-01T00:00:00Z 起的 UTC 毫秒,是墙钟,系统改时间与 NTP 校时都会让它跳变;后者是从页面导航起算的单调时钟,单位毫秒但带小数,且被浏览器降精度到微秒级,不受系统时间调整影响。要跟墙上时间对齐(到某个时刻归零、跨刷新仍成立)必须用前者;只测量「经过了多久」(性能打点)应该用后者。

跨时区与 UTC 陷阱。时间戳本身是 UTC 毫秒,「还剩多少毫秒」在任何时区都一致,会出错的是解析:ECMAScript 规定 2026-10-01 这种纯日期字符串按 UTC 解析,带时间的 2026-10-01T00:00 按本地时间解析,在东八区两者相差 8 小时。本页输入的是 HH:MM,构造目标时刻时显式传入年、月、日、时、分,走本地时间分支,不会踩到这条规则;结果卡同时给出本地与 UTC 时间,方便跨时区核对。另外 Date.now() 不受夏令时影响,但「今天 20:00」这个本地时刻在夏令时切换日可能不存在或出现两次——中国大陆自 1991 年起不再实行夏令时,这个坑主要影响海外用户。

完整示例(数值仅作演示)

这个倒计时器的示例条件与页面默认值完全一致:按持续时长模式,0 时 5 分 0 秒,即 300 秒、300000 毫秒。

这些数字都由「回调平均多花 d 毫秒」这个模型推出,d 取别的值时见下一节对照表;真实环境里 d 会波动,但方向永远是「越走越慢」。

漂移与时钟对照表

下表按 floor(T / (1000 + d)) 逐项算出,「慢多少」= 墙钟秒数 − 累加式显示秒数;误差随时间线性累积,8 小时的误差约为 1 小时的 8 倍。

模型1 小时后显示1 小时慢多少8 小时后显示8 小时慢多少
累加式,额外开销 d = 1 ms3596 秒4 秒28771 秒29 秒
累加式,额外开销 d = 2 ms3592 秒8 秒28742 秒58 秒
累加式,额外开销 d = 5 ms3582 秒18 秒28656 秒144 秒
累加式,额外开销 d = 10 ms3564 秒36 秒28514 秒286 秒
绝对时间基准(本页)3600 秒0 秒28800 秒0 秒

下表假设倒计时一开始页面就被隐藏,按「前 5 分钟每秒一次、之后每分钟一次」推导累加式收到的触发次数:

页面隐藏时长累加式触发次数累加式显示墙钟实际慢多少
5 分钟300 次00:05:0000:05:000 秒
30 分钟325 次00:05:2500:30:0024 分 35 秒
1 小时355 次00:05:5501:00:0054 分 5 秒
8 小时775 次00:12:5508:00:007 小时 47 分 5 秒

最后并排列出两套时钟的适用场景,选错时钟是同类工具里最常见的隐性 bug:

取时方式时钟类型粒度受系统改时间影响适合用来做
Date.now()墙钟(UTC 毫秒)1 ms会跳变与墙上时间对齐的倒计时、跨刷新持久化
performance.now()单调时钟微秒级不受影响测量「经过了多久」、性能打点
new Date().getTime()与 Date.now() 等价1 ms会跳变同上,写法更啰嗦,一般不推荐

输入范围、边界与精度说明

常见问题

切到别的标签页,倒计时会停吗?回来后还准吗?

不会停也不会变慢。页面隐藏时本页主动 clearInterval(不在后台空转),回到前台先算一次 toEnd - Date.now() 再重建定时器。剩余量来自两个绝对时间戳,隐藏多久都不影响结果。

为什么「每次减一秒」的写法会越跑越慢?

setInterval 只保证间隔不小于 1000 毫秒,回调排队让真实周期略大,累加式把「触发一次」当成「过了一秒」,日积月累就欠账。按 5 毫秒额外开销算,1 小时欠 18 秒、8 小时欠 144 秒;切到后台后半小时就能欠出 24 分多钟。

Date.now() 和 performance.now() 该用哪个?

看要对齐哪种时间:要「到某个墙上时刻归零」用 Date.now(),要「量出经过多少毫秒」用 performance.now()(单调时钟,系统改时间不影响它)。本页做的是前者,所以固定用 Date.now()。

电脑自动对时或者我手动改了系统时间,会怎样?

倒计时会跟着系统时间走:往前调剩余变大,往后调变小甚至立刻归零。这是「与墙上时间对齐」的必然结果,不是 bug。NTP 校时通常只有几十毫秒微调,肉眼看不出来。

跨时区的人一起看同一个截止时间,怎么保证一致?

用结果卡里的 UTC 那行。时间戳是 UTC 毫秒,任何时区算出的「还有多久」都相同,会不一致的只有本地化显示。另外 new Date('2026-10-01') 按 UTC 解析、带时间的 2026-10-01T00:00 按本地解析,在东八区差 8 小时。

页面关掉还会响吗?

不会。定时器依附当前页面,关闭标签页就一起销毁。需要关机后仍然生效的提醒请用系统日历;本页适合「人还在电脑前、要盯一个时长或一个时刻」的场景。

为什么倒计时到 0 会晚一点点?

本页每 200 毫秒刷新一次,归零最多晚 0.2 秒显示;内部剩余量一直按绝对时间算,不会因为显示延迟而多算或少算。把间隔调到 1000 毫秒能省开销,但秒数跳动会明显滞后。

我设了 8 小时,中途合盖睡眠了,醒来还准吗?

准。睡眠期间页面不执行但系统时钟在走,醒来后的第一次刷新就得到正确剩余量,通常已归零并提示时间到。虚拟机挂起这类「系统时钟也停」的情况才会偏慢,那是墙钟方案的固有边界。

相关工具