做个倒计时、轮播图自动切页,或者每秒刷新一次时间显示,第一反应基本都是 setInterval。这个定时器好用,坑也不少,展开说说。

基本写法

setInterval(函数, 间隔毫秒数),间隔填 1000 就是每秒执行一次,返回值是一个定时器 id,留着给 clearInterval 用:

const timer = setInterval(() => { console.log(new Date().toLocaleTimeString()); }, 1000);

想给函数传参数,直接写在毫秒数后面:setInterval(fn, 1000, a, b),fn 收到的就是 a 和 b。第一个参数也可以传一段字符串代码,但不建议这么写,调试和压缩都麻烦。兼容性倒不用操心,这是老 API,各家浏览器全支持。

停掉定时器:clearInterval

定时器不会自己停,页面关了才销毁,不用了就手动清:

clearInterval(timer);

经典 bug 是按钮每点一次就新建一个定时器,旧的没清,最后日志一秒打印十几次。正确做法是开新的之前先 clearInterval 掉旧的,或者用标志位防止重复启动。

几个容易踩的坑

  • 函数耗时超过间隔:比如间隔 1 秒但接口请求要 3 秒,任务会堆积排队,页面看起来像卡死,这种情况改用 setTimeout 递归,等上一次跑完再排下一次
  • this 指向变了:普通函数写法里 this 不再指向外层对象,用箭头函数或者在外面先存一份引用
  • 浏览器对后台标签页会把间隔强制拉长,最细一般到 1 秒以上,别拿它做精确计时
  • 框架组件销毁前记得清理:Vue 在 onUnmounted 里、React 在 useEffect 的清理函数里 clearInterval,不然定时器会一直空跑

还有个细节:间隔不是精确的。定时器排在事件循环里,前面有耗时任务就得等,设 1000 实际可能是 1050。要显示得准,就记一个起始时间,每次用 Date.now() 算差值校正。

一句话:js 里 setInterval 负责「每隔多久执行一次」,开了就要记得关,耗时任务换 setTimeout 递归,动画要跟帧就用 requestAnimationFrame。