用 setInterval 驱动彩色时钟:javascript.info 经典实战(DOM 更新与定时器启停管理) 文档/教程前端【免费下载链接】en.javascript.infoModern JavaScript Tutorial项目地址https://gitcode.com/gh_mirrors/en/en.javascript.info点击查看免费下载本篇技术指南基于 Modern JavaScript Tutorialen.javascript.info仓库中 Colored clock with setInterval 练习及其官方解答讲解如何用 HTML/CSS 搭建时钟界面、用 JavaScript 的setInterval周期性刷新 DOM并正确处理定时器的启动、防重入与停止逻辑。读完本文你将掌握timerId守卫式启停模式、new Date()取时与补零技巧、children[i].innerHTML局部更新写法以及setInterval的时序不可靠性与嵌套setTimeout替代方案等关键细节。任务回顾做一个纯前端驱动的彩色时钟该练习位于 2-ui/1-document/07-modifying-document/10-clock-setinterval/task.md要求是创建一个彩色时钟HTML/CSS 只负责样式JavaScript 只负责在元素中更新当前时间。这是一个典型的界面与逻辑分离的 DOM 操作入门任务官方将它的重要性评级设为 4importance: 4属于 Modifying the document 章节末尾的综合练习题。官方解答与完整实现分别保存在同目录下solution.md逐步讲解的官方解答solution.view/index.html可直接运行的完整实现含彩色样式与 Start / Stop 按钮source.view/index.html任务初始框架只有两个按钮clockStart()/clockStop()需自行补齐。第一步用 HTML/CSS 搭出时钟骨架官方解答的第一步是设计结构。为了让时、分、秒三个部分能被 JavaScript 独立更新把每个时间分量放进各自的span外层用一个#clock容器包住div idclock span classhourhh/span:span classminmm/span:span classsecss/span /div这里的hh、mm、ss是占位文本页面加载后会被 JavaScript 立即替换为真实时间。接着用 CSS 为三个span上色。在 solution.view/index.html 中官方使用了经典的三色方案.hour { color: red } .min { color: green } .sec { color: blue }这样一个时-红、分-绿、秒-蓝的彩色时钟界面就完成了。这种语义化 class 独立span的做法正是为了后续可以精确索引每个时间分量clock.children[0]、clock.children[1]、clock.children[2]避免用脆弱的字符串匹配去定位元素。第二步update() —— 读取当前时间并刷新 DOM界面的核心是update()函数它负责读一次当前时间、写一次页面。官方完整实现位于 solution.md 以及 solution.view/index.htmlfunction update() { let clock document.getElementById(clock); let date new Date(); // (*) 每次调用都重新取当前时间 let hours date.getHours(); if (hours 10) hours 0 hours; clock.children[0].innerHTML hours; let minutes date.getMinutes(); if (minutes 10) minutes 0 minutes; clock.children[1].innerHTML minutes; let seconds date.getSeconds(); if (seconds 10) seconds 0 seconds; clock.children[2].innerHTML seconds; }这段代码里有三个值得注意的细节1. 每次调用都重新new Date()行(*)官方解答特别强调setInterval的调用并不可靠可能发生延迟例如浏览器标签页被切走、主线程被其他任务占用时所以绝不能假定调用时刻恰好是整秒。每次update()都基于new Date()重新取当前时刻能保证时钟显示的是真实当前时间而不是上次时间 1 秒的推算值从而避免误差累积。2. 补零处理getHours()/getMinutes()/getSeconds()在小于 10 时返回单个数字如9、5直接显示会破坏hh:mm:ss的固定宽度格式。解答用if (hours 10) hours 0 hours;统一补前导零让 9 点显示为09。3. 通过children索引 innerHTML局部更新clock.children[0]/[1]/[2]分别对应第一个、第二个、第三个子元素即三个span。innerHTML赋值会在不触碰其他兄弟元素的前提下只替换目标span的内部内容——这正是 Modifying the document 章节介绍的innerHTML核心用法读取元素内 HTML 内容或写入新内容将其替换。整个页面中只有这三个span被刷新无需重建整个时钟节点开销极小。第三步clockStart() / clockStop() —— 定时器的启停管理时钟要每秒刷新一次需要setInterval周期性调度update。但直接写一个setInterval是不够的真正的工程要点在于启停管理。官方解答solution.md给出的管理函数如下let timerId; function clockStart() { // 启动时钟 if (!timerId) { // 只有当时钟未运行时才创建新定时器 timerId setInterval(update, 1000); } update(); // (*) 立即刷新一次不等第一个 1 秒 } function clockStop() { // 停止时钟 clearInterval(timerId); timerId null; // (**) 置空 timerId允许再次启动 }这里包含了四个极易踩坑的细节1.if (!timerId)守卫防止重复启动产生并发定时器如果用户连续点击 Start 按钮而没有这层守卫每次点击都会创建一个新的setInterval多个定时器并发执行更糟的是timerId变量每次被覆盖最终只保存了最后一个定时器的引用前面的定时器全部失联永远无法停止。守卫写法确保运行中就不再新建同一时刻至多存在一个定时器。2. 启动后立即调用update()行(*)setInterval(update, 1000)意味着第一次执行要等 1 秒后才发生。如果不立即调用一次update()页面加载/点击启动后时钟会空置整整 1 秒才显示时间。官方解答明确点出否则访问者必须等到setInterval的第一次执行期间时钟将是空的。3.clearInterval与timerId null配对行(**)clearInterval(timerId)负责真正终止定时器随后把timerId置为null同样关键——它向clockStart()发出时钟已停止的信号。若省略这一步停止后timerId仍持有旧的已失效的ID再点 Start 时if (!timerId)判断为假定时器将永远无法再次启动。4. 顶层let timerId的共享作用域timerId声明在函数之外供clockStart()写入、clockStop()清除作为两个函数之间共享的状态标志。这种函数 外部变量的组合模式正是后续 Closure 章节所讲闭包与共享词法环境的雏形。完整可运行代码将以上部分合并就是一个可直接保存为.html运行的最小时钟页面对应官方 solution.view/index.html!DOCTYPE HTML html head style .hour { color: red; } .min { color: green; } .sec { color: blue; } /style /head body div idclock span classhourhh/span:span classminmm/span:span classsecss/span /div script let timerId; function update() { let clock document.getElementById(clock); let date new Date(); let hours date.getHours(); if (hours 10) hours 0 hours; clock.children[0].innerHTML hours; let minutes date.getMinutes(); if (minutes 10) minutes 0 minutes; clock.children[1].innerHTML minutes; let seconds date.getSeconds(); if (seconds 10) seconds 0 seconds; clock.children[2].innerHTML seconds; } function clockStart() { // 只有当时钟停止时才创建新定时器 // 否则会覆盖运行中定时器的引用导致无法再停止 if (!timerId) { timerId setInterval(update, 1000); } update(); // 立即刷新不必等 1 秒 } function clockStop() { clearInterval(timerId); timerId null; // 标记已停止允许再次启动 } /script input typebutton onclickclockStart() valueStart input typebutton onclickclockStop() valueStop /body /html原理深挖setInterval 的时序、内存与替代方案要真正理解这份解答还需要从定时器原理层面看透三个关键点官方在 Scheduling: setTimeout and setInterval 章节中有完整论述。setInterval 的实际间隔比代码写的更短setInterval(func, delay)的语义是每delay毫秒运行一次func。但官方指出实际两次调用之间的间隔往往小于声明的delay。原因是func自身的执行时间会吃掉一部分间隔——调度器按固定周期把func塞进任务队列若func执行耗时较长前一次尚未结束、下一次回调已到期引擎会在当前调用结束后立即再次执行甚至出现连续无停顿执行的情况这正好印证了update()里每次重新new Date()的必要性既然回调触发时刻本就可能漂移显示的值必须以触发时刻的真实时间为准。嵌套 setTimeout更精确的替代方案官方将固定间隔执行的另一种写法——嵌套setTimeout与setInterval做了对比let timerId setTimeout(function tick() { // ... 执行任务 timerId setTimeout(tick, 2000); // 在上一次结束后才安排下一次 }, 2000);区别在于setInterval是固定节奏排队函数执行时间会压缩实际间隔而嵌套setTimeout是在本次执行结束之后才规划下一次调用因此能保证两次执行之间的间隔相对固定此外嵌套setTimeout还允许根据本次执行结果动态调整下一次的延迟例如服务器过载时把轮询间隔翻倍。对本任务而言setInterval已足够简洁若要追求秒针与真实秒的精确对齐可将update改写为嵌套setTimeout并动态计算距离下一整秒的毫秒数。定时器回调与垃圾回收官方 Garbage collection and setInterval/setTimeout callback 一节还提醒了一个隐蔽的内存问题当函数被传给setInterval/setTimeout时调度器内部会持有该函数的引用防止其被垃圾回收。对setInterval而言这个函数会一直驻留内存直到调用clearInterval。因此不需要时就及时clearInterval不仅是为了停止行为也是及时释放定时器回调及其闭包引用的外部变量的内存。这也解释了为何clockStop()必须同时完成终止 置空引用两个动作。另外一个浏览器层面的限制是5 层以上嵌套的setTimeout或第 5 次之后的setInterval调用浏览器强制最小延迟为4ms历史原因这也再次说明定时器精度并非无限可靠不能依赖它做高精度计时。扩展思考从这份解答还能学到什么textContent与innerHTML的选择本例写入的是纯数字字符串用innerHTML完全可行但如果将来要写入用户输入等不可信内容应改用textContent以避免意外的 HTML 解析与注入风险。状态管理的雏形timerId作为是否运行中的状态标志是许多 UI 组件启停互斥逻辑的通用写法可迁移到轮播图、轮询、动画等任何需要周期性任务的场景。界面与逻辑分离HTML/CSS 只管展示、JS 只管刷新数据这种结构让时钟可以被轻松复用到其他项目中只需复制update 启停函数并保证三个span的顺序与children索引一致。仓库中还包含多个同主题的练习题如 1-output-numbers-100ms用于进一步巩固setInterval的启停与嵌套setTimeout的写法可作为本练习之后的进阶训练。赞分享文档/教程前端【免费下载链接】en.javascript.infoModern JavaScript Tutorial项目地址https://gitcode.com/gh_mirrors/en/en.javascript.info点击查看免费下载相关推荐ToolJet 定时查询实战利用 RunJS 与 setInterval 在指定时间间隔自动运行查询ToolJet 定时查询实战利用 RunJS 与 setInterval 在指定时间间隔自动运行查询 本文是一份面向 ToolJet 应用构建者的实战指南核低代码后端前端AI 应用MCP 服务深入理解 JavaScript 定时调度setTimeout 与 setInterval 实战指南深入理解 JavaScript 定时调度setTimeout 与 setInterval 实战指南 导读 在 JavaScript 开发中我们常常需要延迟文档/教程前端Zephyr RTOS实时时钟(RTC)驱动开发与时间管理Zephyr RTOS实时时钟 RTC 驱动开发与时间管理 在嵌入式系统开发中实时时钟RTCReal Time Clock是关键组件负责提供精确的时间操作系统嵌入式RTOS物联网上一篇如何掌握ag-ui异常处理错误捕获与恢复机制完整指南下一篇Epoxy与Paging3集成无限滚动列表实现方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考