最推荐用 setInterval 实现每秒时间更新,因其简单、兼容性好且稳定;需确保 DOM 就绪、用 textContent 写入、补零格式化、每次调用 new Date(),避免 setTimeout 递归导致的误差累积。

直接用 setInterval 每秒调用一次时间更新函数,是最简单、兼容性最好、也最不容易出错的方案。其他方法(比如 requestAnimationFrame)在特定场景下有优势,但对绝大多数页面来说属于过度设计。
用 setInterval 实现每秒刷新
核心就是定时执行一个获取并写入时间的函数。关键点不是“怎么写”,而是“怎么写得稳”:
- 确保 DOM 元素已存在再操作,推荐把脚本放在
</body>前,或监听DOMContentLoaded事件 - 用
textContent替代innerHTML写入纯时间字符串,避免 HTML 解析开销和潜在 XSS 风险 - 格式化时注意补零:比如
hours.toString().padStart(2, '0'),否则 9:5:7 会显示成 9:5:7 而不是 09:05:07 - 别在
setInterval外部定义时间变量,每次都要调用new Date()获取实时值
为什么不用 setTimeout 递归?
网上有些示例用 setTimeout + clearTimeout 手动递归调用,看似可控,实际容易漏掉清除逻辑,导致多个定时器同时运行。更麻烦的是,它无法保证严格 1 秒间隔——如果某次执行卡顿,下次就会延迟,误差会累积。而 setInterval 是浏览器原生调度,只要主线程不长时间阻塞,节奏就稳定得多。
什么时候该考虑 requestAnimationFrame?
只在两种情况下值得换:需要毫秒级精度显示(比如倒计时到 0.1 秒),或者页面有大量动画且你发现 setInterval 更新造成掉帧。它本身不按秒触发,得你自己判断秒数是否变化再更新 DOM,代码反而更啰嗦。多数时钟根本不需要这个级别控制。
立即学习“前端免费学习笔记(深入)”;
容易被忽略的兼容性细节
中文星期、月份名不能靠 toLocaleString() 直接拼——不同浏览器对 Intl.DateTimeFormat 的支持程度不一,尤其是旧版 Safari。稳妥做法是用数组映射:
const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; const now = new Date(); const weekday = weekdays[now.getDay()];
另外,getMonth() 返回的是 0–11,直接加 1 就行,但很多人在这里写错成 +12 或漏加,结果月份永远少一个月。



















