刚接触javascript时对定时器进行过总结,但也只是停留在函数的用法。最近在看「JavaScript高级程序设计」,再次看到相关的内容,涉及到事件循环[Event Loop],才对这两个方法的调用原理有清晰的认识,做个笔记先。

任务队列

JavaScript是单线程语言,一段时间内只能执行一段代码。为了控制要执行的代码,出现了JavaScript执行栈,这些任务按照他们被添加在执行栈中的顺序依次执行。前一个任务结束,才会执行下一个任务,如果没有执行完,那么下一个任务必须一直等着,但是这种方式在一些情况下会造成CPU闲置(例如IO设备慢,但是CPU却一直干等着),造成资源浪费。于是将任务分为同步任务与异步任务,同步任务进入主线程,而异步任务则先进入任务队列进行等待。等待执行栈的所有任务执行完毕,任务队列中的任务才能进入主线程,排队执行。setTimeout()与setInterval()则是属于异步任务,需要先进入任务队列。

定时器执行

setTimeout()与setInterval()调用的本质都是相同的,区别在于setTimeout()只调用一次,而setInterval()是按照指定的时间重复调用,两个方法在被调用之后会返回一个ID,这个ID是计划执行代码的唯一标识符,可以用来取消调用。

1
2
3
4
setTimeout(function(){
console.log(1);
},1000);
console.log(2);

代码运行的过程:
setTimeout()开始计时
console.log(2);进入主线程,因为没有阻塞,直接执行
执行结束,主线程空了,查询任务队列,因为时间还没到1000ms,任务队列为空,事件循环继续
达到1000ms,setTimeout()的回调函数被抛进任务队列,任务队列被再次查询时,console.log(1);进入主线程,执行。

所以setInterval()和setTimeout()都无法保证绝对的”准时”,只会迟,不会早。

特殊情况

setInterval()会重复调用,当上一次抛进任务队列的回调函数仍在排队,新添加的回调会被kill。

总结

在之前的学习中没能做到知其所以然,温故而知新,及时记下并且消化,共勉!

听说最近这个结尾很高冷。

以上。