setInterval 的弊端和解决方案
setinterval不会清除定时器队列,每重复执行1次都会导致定时器叠加,最终卡死你的网页
其原因与JS引擎线程有关(又得研究下JS引擎线程了) 但是setTimeout是自带清除定时器的
setTimeout表示间隔一段时间之后执行一次调用,而setInterval则是每间隔一段时间循环调用,直至clearInterval结束。 内存方面,setTimeout只需要进入一次队列,不会造成内存溢出,
setInterval因为不计算代码执行时间,有可能同时执行多次代码, 导致内存溢出。
弊端1:setInterval会无视错误代码,即使代码报错,还是会一直执行下去。
弊端2:setInterval会无视网络延迟,很多人会有需求需要1秒更新一次数据,然后就有可能会定时发送请求给服务器请求,假如服务器请求数据发生延迟等等情况的时候,setInterval不会等到请求数据完之后才去去执行下一次请求,他会在当你发生第一次请求的时候就已经开始计时,并且无论有没有请求完成,只有时间一到下一秒的时候,就会再次发送请求。很容造成请求堵塞,或者渲染堵塞,严重的会之间卡死。
注:vue 项目的时候,如果页面使用到循环定时器,调用后台接口出现异常,在切换路由地时候并不能清除定时器。(目前我测试出来,是这样的)
beforeRouteLeave(to, from, next) {
console.log('beforeRouteLeave')
this.clearTimer()
next() // 一定不要忘记写, 否则无法跳转路由
}
弊端3:很多时候越跑越快的问题。
使用setInterval()的问题在于,定时器代码可能在代码再次被添加到队列之前还没有完成执行,结果导致定时器代码连续运行好几次,而之间没有任何停顿。而JavaScript引擎对这个问题的解决是:当使用setInterval()时,仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中。这确保了定时器代码加入到队列中的最小时间间隔为指定间隔。
但是,这样会导致两个问题:
解决方案:使用setTimeout和递归(自我调用)
使用 setInterval 方案(不推荐使用)
setInterval(function () {
console.log('做点什么吧')
}, 1000)
使用 setTimeout 方案 (推荐使用,完美代替setInterval) 注:有待验证
var demo = function () {
console.log('做点什么吧')
setTimeout(demo, 1000)
}
使用setTimeout代替setInterval。
可以给setTimeout设置时间后,在最后调用自身。如果希望“匀速”触发。可以计算代码执行时间,用希望的延迟减去上次执行的时间。
注:有一种想法是将setInterval的延迟时间设置的长于上述的几种时间,来达到绝对的均速调用。但事实上,js的计时器因为自身机制的原因,存在4ms–15ms的误差。
来源整理自:vue3js.cn 面试官系列



