setTimeout和setInterval和单线程
我们知道,js是单线程执行的(单线程j就是说在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行)。所以其实setTimeout和setInterval所谓的“异步调用”事实上是通过将代码段插入到代码的执行队列中实现的。
而如何计算插入的时间点呢?自然是要用到我们所说的timer,也就是计时器。当执行setTimeout和setInterval的时候,timer会根据你设定的时间“准确”地找到代码的插入点。当队列“正常”地执行到插入点时,就触发timer callback,也就是我们设定的回调函数
注意还有一种情况
刚刚已经知道,事实上setTimeout和setInterval只是简简单单地通过插入代码到代码队列来实现代码的延迟执行(或者说异步执行)。但是事实上所谓的异步只是一个假象——它同样运行在一个线程上! 始终是单线程!
那么问题就来了,要是在代码插入点前的代码执行时间超过了传入setTimeout或setInterval的设定时间会怎样呢?让我们来看看这段代码:
function fn() { setTimeout(function(){alert('can you see me?');},1000); while(true) {} }
执行结果alert永远不会出现。
因为,while这段代码没有执行完(如图,浏览器一直在解析while的代码),所以插入在后面的代码便永远不会执行。
综上所述,其实JS终归是单线程产物。无论如何“异步”都不可能突破单线程这个障碍。所以许多的“异步调用”(包括Ajax)事实上也只是“伪异步”而已。
再看下面一段代码:
function run(){ // 其他代码 setTimeout(function(){ run(); }, 10000); } run();
以上面的代码来说, 虽然设置的是10s执行一次, 但是实际时间却是需要// 其他代码
的执行时间来确定
即setTimeout的间隔时间是, // 其他代码
执行时间 + 10s
setInterval(function(){ run(); }, 10000);
而setInterval, 不会有上面的问题, 但是如果run()
的执行时间, 操作大于10s, 那么甚至可能跳过run()任务