关键在“怎么稳”:确保DOM加载完成再执行,用textContent而非innerHTML写入时间,每500ms检查秒数变化再更新DOM,并用padStart补零保证格式统一。

直接用 setInterval 配合 Date 对象就能跑起来,但写错一行就可能卡住、跳秒、XSS 漏洞或首次加载空白——关键不在“能不能”,而在“怎么稳”。
确保 DOM 加载完成再执行时间更新
脚本如果在 <div id="clock"></div> 元素之前执行,document.getElementById('clock') 会返回 null,后续所有操作都静默失败。
- 把
<script>放在</body>前是最简单可靠的方案 - 或者用
document.addEventListener('DOMContentLoaded', ...)包裹初始化逻辑 - 别依赖
window.onload,它等全部资源(含图片、CSS)加载完才触发,延迟明显
用 textContent 而不是 innerHTML 写入时间
时间字符串不含 HTML 标签,用 innerHTML 不仅多余,还可能意外解析恶意内容(比如 URL 中带 <script> 片段时)。
-
document.getElementById('clock').textContent = now.toLocaleTimeString();更安全、更快 - 如果硬要用
innerHTML,必须先做转义(例如用DOMPurify.sanitize()),得不偿失 - 现代浏览器对
textContent的 DOM 更新优化更好,尤其在高频更新场景下
避免每毫秒都重绘:只在秒变化时更新
setInterval(updateTime, 1000) 看似合理,但实际执行时机受 JS 主线程阻塞影响,可能累积误差,甚至出现“跳两秒”现象;而 requestAnimationFrame 又太频繁(60fps 下每 16ms 一次),纯属浪费。
立即学习“前端免费学习笔记(深入)”;
- 推荐做法:用
setInterval每 500ms 检查一次当前秒数是否变化,仅当变化时才调用 DOM 更新 - 代码核心逻辑:
if (now.getSeconds() !== lastSecond) { updateDOM(); lastSecond = now.getSeconds(); } - 这样既保证视觉上“每秒一跳”,又避免无效 DOM 操作,对低端设备更友好
格式化小时/分钟/秒时必须补零
直接拼接 now.getHours() + ':' + now.getMinutes() 会导致 9:5:7 这种显示,不符合阅读习惯,也破坏 CSS 宽度预设(如固定宽度容器会抖动)。
- 用
String(now.getHours()).padStart(2, '0')是最简洁可靠的方式 - 别手写
h ,容易漏判负数或 NaN 边界情况 - 注意
getMonth()返回 0–11,要加 1;getDate()才是 1–31,无需额外处理
真正难的不是让时间动起来,而是让动得准、动得稳、动得不拖慢页面——补零、检查秒变化、用 textContent、等 DOM 就绪,这四件事漏掉任何一个,上线后都可能被用户截图发群里问“为啥我们的时间老卡住”。



















