今天跟大家伙儿唠唠我捣鼓 `*` 的那些事儿。一开始我对这玩意儿也是一知半解,就知道它是个定时器,能让代码隔一段时间跑一次。但是真正用起来,那踩的坑,可真不少!
事情是这样的,前阵子接个小项目,要在网页上搞一个简单的倒计时功能。一开始我的想法很简单,用 `setTimeout` 定时刷新页面上的时间显示就完事儿。但是后来发现,`setTimeout` 只能执行一次,要实现倒计时还得递归调用,感觉有点麻烦。
然后我就想到 `setInterval` 这家伙。心想,这玩意儿不是能循环执行吗?正合我意!于是我就开始撸代码,直接 `*(updateTime, 1000)`,意思就是每隔1秒钟调用 `updateTime` 函数来更新时间。
一开始跑起来,感觉还不错,时间一秒一秒地跳,挺有仪式感。但是问题很快就来。我发现,如果我快速切换页面或者做一些比较耗时的操作,这个倒计时的时间就会开始变得不准,甚至会直接卡住。
这下我就懵,心想 `setInterval` 不是很靠谱的定时器吗?怎么还会出这种幺蛾子?于是我就开始各种查资料,各种调试。
后来我才明白,原来 `setInterval` 并不是想象中的那么完美。它最大的问题就是,它不会管你之前的任务有没有执行完,到时间就直接开始执行下一个任务。如果你的任务执行时间超过设定的间隔时间,就会出现任务堆积的情况,导致时间不准。
举个例子,假设我设置的间隔时间是1秒,但是 `updateTime` 函数因为某些原因执行1.5秒。那么 `setInterval` 不会等你 `updateTime` 执行完,到1秒的时候它还是会启动一个新的 `updateTime` 任务。这样一来,就会有两个 `updateTime` 任务同时运行,时间肯定就不准。
找到问题所在,解决起来就容易多。我把 `setInterval` 换成 `setTimeout`,然后在 `updateTime` 函数执行完毕之后,再调用 `setTimeout` 启动下一个任务。这样就保证每次只有一个 `updateTime` 任务在执行,避免任务堆积的问题。
代码大概是这样:
javascript
function updateTime() {
// 更新时间的代码
// ...
// 执行完毕后,启动下一个任务
setTimeout(updateTime, 1000);
// 首次启动
setTimeout(updateTime, 1000);
这样改完之后,倒计时的时间就准确多,即使切换页面或者做一些耗时操作,也不会出现时间不准的问题。
通过这回实践,我算是彻底搞明白 `setInterval` 和 `setTimeout` 的区别,也明白在什么情况下应该选择哪一个。
`setInterval` 适合那些对时间精度要求不高,而且任务执行时间比较短的情况。而 `setTimeout` 则更适合那些对时间精度要求比较高,或者任务执行时间不确定的情况。
`*` 这东西,看着简单,用起来还是有很多门道的。希望我的这回实践记录能对大家有所帮助,少踩一些坑。