setInterval和任务队列
问题的来源
应该很多人都知道js单线程但是能完成异步的原因。
处理setTimeout的模块会在延迟时间后把要执行的任务推入任务队列,直到js线程上下文栈为空,那么setInterval这种每隔一段时间执行函数的情况呢?
(以下函数测试环境为Chrome)
实验一
1 | var t = setInterval(function () { |
这段代码意思就是创建了一个setInterval,每一秒打印当前时间,但是我用一段循环阻塞了5秒钟。
最开始的想法:每一秒钟,都会在任务队列中推入一个任务即打印当前时间。也就是阻塞5秒后会立即输出四行。
结果的话…
在5秒后,控制台慢慢悠悠地每隔一秒输出当前时间,也就是最开始的想法是不对的…
实验二
1 | var t = setInterval(function () { |
是的我就加了一行clearInterval,也就是5秒循环后把定时器给停了。
结果倒是和我想的一样,5秒后什么都没发生…
如果在控制台console.log(t)
会输出一个数字,或者控制台输入window.t
会返回同样的数字。
到这里我的猜想是,浏览器模块处理一个setInterval时候只会把任务推入任务队列一次,直到js线程把任务取出执行,模块再根据延时把任务推入任务队列。
实验三
验证方法就是再来一个setInterval
1 | var t = setInterval(function () { |
结果:
当然如果在while后加一行clearInterval(t),那么输出的只有计时器g的结果了
脑测结论
- 处理setInterval的模块会保存这个计时器的状态,延时到了就会把任务推入任务队列,在该任务被取出之前,计时器就相当于一个静止状态。
- 如果遇到了clearInterval,那么模块中的Interval和任务都会被移除。
真正的原理不知道…
bug
看了一看实验三的结果,前两个g的输出时间仅差了一秒钟,后续的g则按照2秒输出一次的规则进行….这部分研究完再更新吧