一、setTimeout的内部执行顺序
setTimeout(code, ms)函数是指在指定的毫秒数(ms)后调用函数或执行代码块,并返回一个整数,后续可以通过clearTimeout(num)传递这个整数来取消该定时器。
setTimeout(function(){
console.log(1);
},0);
console.log(2);
一个很普通的setTimeout定时器,运行上面的代码输出的结果是2、1,但是明明定时器是:在0ms也就是“立即”执行log(1),然后再log(2)啊,结果顺序却是反的,甚至在log(2)之前加上一个耗时的处理也不会影响这个输出结果:
varstartTime = +newDate();
setTimeout(function(){
console.log(1);
},0);
while((+newDate() - startTime) < (1000*3)) {
// console.log('...');
}
console.log(2)
以上加了一个3秒的while循环阻塞进程,按正常理解log(2)需要在log(1)后3秒才会输出,但输出结果还是跟之前一样,下面逐步分析这种情况的原因。
二、
JavaScript是单线程的语言,在执行时必须等前面的任务处理完以后才会处理后面的;而且是一个一个连续同步执行的,不象多线程可以同时处理多个任务。JavaScript中的任务分为同步任务和异步任务,同步任务就是主线程上一个个排队执行的任务;相反的异步任务则不进入主线任务而是被加入到“任务队列”中,任务队列的任务只有在主线任务执行完成之后才去处理任务队列中的任务。
所以上面的问题:setTimeout(function(){console.log(1);}, 0);
这里的0代表的是0秒后加入到任务队列并没有执行,他要等主线程上面的任务"console.log(2)"执行完成后才会执行。
setTimeout、setInterval和回调这两种形式的程序会添加到任务队列,来看下面的例子:
functionfoo(){
console.log(1);
}
functionbar(){
console.log(2);
}
foo();
bar();
$('#btn').on('click',function(){
console.log(3);
});
setTimeout(function(){
console.log(4);
},0);
主线程上的任务就是执行foo()、bar()和后面的事件绑定和设定定时器,而任务队列中有一个事件回调任务和一个定时器任务,主线程foo()、bar()执行结束后,就会查看任务队列中的任务,然后“全部执行”。所以setTimeout(code, ms)表示的是ms后把code任务添加到队列,而不是说ms后就会执行,就算setTimeout时间设置成0,他也要等主线程上的任务完成才会执行,所以setTimeout的执行时间并不是准确的,真正执行的时间要比设定的时间大。
网友评论