这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
现象
最近在开发一个活动,里面有涉及到倒计时,主要逻辑是:
一进入页面就获取活动的信息,在活动信息里有活动的开始时间,如果活动开始时间还没到,就显示倒计时。然后在页面还有别的任务可以完成,当你完成任务的时候是会刷新活动的信息的。
我用代码简单模拟一下:
function fn(date) {
let now = date
setInterval(() => {
let date = formatTime(now)
now = now + 1000
document.querySelector('div').innerText = date
}, 1000)
}
// 模拟一进入页面获取活动信息
fn(+new Date())
// 模拟完成任务重新获取活动数据
document.querySelector('button').onclick = () => {
fn(+new Date())
}
效果如下所示(这个我是用qq的录屏功能来录制的,大家如果有mac上用的比较好的录屏工具,欢迎推荐)
大家可以清晰看到,数字一直在跳动,数字变小后再变大,这样的体验肯定是过不了测试人员那关的,
于是提了bug,让我改。
解决
于是我就想,为什么数字会跳动呢? 到底是什么影响了呢?
最后才发现,我每次调用fn函数,里面都会调用一个setInterval去刷新时间,但是我调用的时候我并没有把上一次的setInterval清除掉,导致页面就会存在2个setInterval在一直调用,然后由于js单线程的原因,有可能会延时,导致2个setInterval内的倒计时执行不是同步的,导致数字会跳动。
所以我就在fn函数里面,每次在设置setInterval的时候都先把上一次的setInterval先清除掉,然后再setInterval。
模拟代码如下:
let timer = null
function fn(date) {
let now = date
// 这个是重点,每次都clear掉
clearInterval(timer)
timer = setInterval(() => {
let date = formatTime(now)
now = now + 1000
document.querySelector('div').innerText = date
}, 1000)
}
// 模拟一进入页面获取活动信息
fn(+new Date())
// 模拟完成任务重新获取活动数据
document.querySelector('button').onclick = () => {
fn(+new Date())
}
解析:
setInterval每次都会返回一个值,我们可以通过这个值来调用clearInterval可以取消掉setInterval,所以我是设置一个timer变量,来存储这个返回值,在每次调用setInterval之前先把它clearInterval,这样就不会影响了。
运行效果如下:
这里可能由于录屏原因导致数字会跳动的快一点,实际上看到的数字是正常每隔一秒跳动的。
总结
所以大家在遇到setInterval或者setTimeout函数时,如果需要重复调用,请务必在之前先调用对应的clear方法,clearInterval或者clearTimeout,取消掉上一次的函数的调用。
感谢大家的阅读。