setTimeout(() => {
console.log(1);
}, 20);
console.log(2);
setTimeout(() => {
console.log(3);
}, 10);
//setTimeout(() => {
// console.log(3);
//}, 70); 如果把这个时间改成70,这个执行顺序可能会不变,可能会到最后一个。因为for循环用时是66-71ms不定,所i有执行时机也就 不确定
//以这个setTimout为例,在for循环结束阻塞之后,并运行完所有同步代码之后,就开始找异步进行处理了
//这个10ms的setTimout代码,从加到异步消息队列到被真正执行上,用时,70ms左右
console.log(4);
console.time("AA");
for(let i = 0; i < 90000000; i++){
//do somthing这里为了代码阻塞
}
console.timeEnd('AA'); //67ms左右不固定
console.log(5);
setTimeout(() => {
console.log(6);
}, 8);
console.log(7);
setTimeout(() => {
console.log(8);
}, 15);
console.log(9);
//结果输出:
// 2 4 时间长 5 7 9 3 1 6 8
//在代码从上到下执行时优先执行console.log/time/timeEnd,然后将setTimeout添加到宏任务列队中,在for循环阻塞前先加了两个setTimeout,阻塞后又加了2个。所以在主栈代码执行完成后开始执行列队中的任务,因为阻塞前的先添加进去的所以优先按顺序执行,然后再执行阻塞后的即后添加到列队中的。
console.time("AA");
console.timeEnd("AA");
相当于一个时间戳记录下中间代码运行时常
总结(我个人总结出的一个规律,不知道对不对)
在for循环会造成阻塞的情况下:
- 写在for循环前边的setTimout事件的延迟时间要是小于for循环阻塞时间,那么就必然优先于for循环后边的setTimout先执行,(我的理解是比如for循环用时70ms,forq前边的setTimout延迟时间是30ms,那么我们在一开始预编译过程,看到setTimeout就会把它加到消息队列,然后30ms到了就把他加到任务队列,等待被调用。而在30ms时,for阻塞还没有走完,即使for后有延迟为0的定时器,这个0的定时器也要等这这些小于for阻塞时间的定时器回调执行完)
- 写在for循环前边的setTimout事件的延迟时间要是大于for循环阻塞时间,那么其实 这个for循环真正的延迟时间应该是(比如for循环用时70ms,for前边的setTimout延迟时间是80ms,for循环结束后,大约还有(80-70 = 10ms)的时间才会被加到执行队列,此时就可以用这个10ms去和for下边的其他的setTimout延迟时间比较了,就按照惯例执行 )
- 写在for循环前边的setTimout事件的延迟时间要是和for循环阻塞时间,大于或是小于在一个很小的范围值内(这个值我没有测),那么输出顺序是会变化的
欢迎大佬指正不对的地方!