最近在准备面试,对于 JS 原理性的文章,感觉很有必要系统整理下,不必每一次都要查询资料,节约时间。
问题
setTimeout(function(){
console.log(“ 开始执行定时器回调: “+ new Date())
console.log(“ 我是定时器 ”)
},0)
大家觉得这个定时器定时时间设为 0,有意义吗?是否觉得上述代码效果等同于
console.log(“ 开始执行定时器回调: “+ new Date())
console.log(“ 我是定时器 ”)
实践是检验真理的最好途径。我们不排斥拿来主义,但是如果能自己实践验证,对于提升自身格物致知的精神很有裨益。针对上述问题,我们用两个实验来解开答案:实验一:
console.log(“1”)
console.log(“ 我是定时器 ”)
console.log(“2”)
打印结果
实验二:
console.log(“1”)
setTimeout(function(){
console.log(“ 我是定时器 ”)
},0)
console.log(“2”)
打印结果
通过上述两个实验结果,我们可以得知 定时器定时为 0 时,JS 执行到定时器这一步,并不是直接开始执行定时回调,而是执行了后续代码之后,才执行。
那为什么会这样呢?我们仍然拿两个例子来说明:实验三:
console.log(“1”)
console.log(“ 定时器线程开始计时: “+ new Date())
setTimeout(function(){
console.log(“ 开始执行定时器回调: “+ new Date())
},5000)
for(var i=0;i<500;i++){
console.log(“ 我是循环 ”)
}
console.log(“ 事件队列最后一位: “+ new Date())
打印结果:
从结果中可以看出,从定时器线程开始定时,到定时 5 秒结束后,将定时回调事件放入事件队列中执行,用了 5 秒。
实验四:
console.log(“1”)
console.log(“ 定时器线程开始计时: “+ new Date())
setTimeout(function(){
console.log(“ 开始执行定时器回调: “+ new Date())
},5000)
for(var i=0;i<50000;i++){
console.log(“ 我是循环 ”)
}
console.log(“ 事件队列最后一位: “+ new Date())
打印结果:
从结果中可以看出,从定时器线程开始定时,到定时 5 秒结束后,将定时回调事件放入事件队列中执行,用了 9 秒。
两次结果不一致,是因为 JS 代码执行到定时器时,此时定时器线程开始定时,定时时间到之后,将定时回调事件推入事件队列而最后,JS 线程依据事件队列中顺序执行。而之所以有的延时 5 秒,有的延时 9 秒,是因为如果定时器开始计时时,JS 事件队列中执行剩余的事件小于 5 秒,则定时结束后,将定时回调事件推入队列中,JS 能够立即执行定时回调事件,所以是 5 秒;而如果 JS 事件队列中执行剩余的事件大于 5 秒,那么在定时结束后,将定时回调事件推入队列后,还需一些时间来执行定时回调事件之前的事件,所以为 9 秒。