Twlig / issuesBlog

MIT License
3 stars 0 forks source link

为什么setTimeout()比setInterval()稳定 #73

Open Twlig opened 2 years ago

Twlig commented 2 years ago

js引擎是单线程的,主要分为主线程和事件队列,同步操作是在主线程上执行,一些异步时间或者是未能马上被主程序执行的函数,一般会先放在事件队列当中,等到js主线程空闲了,才会去事件队列取出事情放到主线程。

定时器是属于异步事件,参数里面设置的时间,并不是延迟多少秒去执行回调函数,这个时间代表的是延迟多少秒,把回调函数放到异步队列,等待主线程空闲再被执行。

setInterval()的问题

问题: 使用setInterval()的问题在于,定时器回调函数再次被添加到队列之前还没有完成执行,结果导致事件队列中有多个定时器回调函数,连续运行好几次,而之间没有任何停顿。这样就失去了每隔一段时间触发回调的初衷。

解决方案:js引擎对这个问题的解决方法就是,当使用setInterval()时,仅当事件队列中没有该定时器的回调函数时,才将定时器回调函数添加到事件队列中。确保回调函数执行最小时间间隔为指定间隔

产生新问题:但是,这样就会导致一些间隔被跳过了。如果功能需求是必须要每个定时器的回调函数都有被执行到,这里就不能满足需求了。

使用setTimeout建立更可靠的间隔执行回调

为了避免setInterval()定时器的问题,可以使用链式setTimeout()调用

setTimeout(function fn(){
    setTimeout(fn,interval);
},interval);

这个模式链式调用了setTimeout(),每次函数执行的时候都会创建一个新的定时器。第二个setTimeout()调用当前执行的函数,并为其设置另外一个定时器。这样做的好处是,在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,就不会产生连续执行回调的情况,也确保了不会有任何缺失的间隔。

参考文章:为什么setTimeout()比setInterval()稳定