老实说,写这篇文章的时候心里是有点压抑的,因为受到打击了,为什么?就 因为喜欢折腾不小心看到了这个"简单"的函数:
for (var i = 0; i < 5; i++) { setTimeout(function () { console.log(i) }, i * 1000); } console.log(i);
什么?这不就是我很久之前看到的先打印一个5,再打印一个5,之后每隔一秒就打印一个5,直到打印完6个5的实现方法吗?那么问题来了,如果我要依次打印0,1,2,3,4,5的话我该怎么办,其实在这之前我就知道有这两个方法:一个是这样:
function log(i){setTimeout(function(){console.log(i)},i*1000)};for (var i = 0; i < 5; i++) { log(i) ; } console.log(i);
还有一个是这样:
for(var i=0;i<5;i++){(function(e){setTimeout(function(){console.log(e)},i*1000);})(i);};console.log(i);
不怕笑话,在这之前我是没搞懂这两个函数真正意义上的作用是用来干嘛的,只强迫自己这样记住这样修改就可以了,但是现在不行啊,我有强迫症啊!于是,我慢慢分析了一下,发现上面那段代码可以分离成这样:
i=0时;满足条件;
setTimeout(function(){console.log(i)},0*1000);
i=1时;满足条件;
setTimeout(function(){console.log(i)},1*1000);
i=2时;满足条件;
setTimeout(function(){console.log(i)},2*1000);
i=3时;满足条件;
setTimeout(function(){console.log(i)},3*1000);
i=4时;满足条件;
setTimeout(function(){console.log(i)},4*1000);
i=5时,不满足条件,跳出循环,接着执行for循环后面的console.log(i),打印5;最后依次每秒打印5;
真有意思,为什么setTimeout里面的console.log会是后于for循环外面的console.log执行呢?直到我认识到了这个单词=>"队列", 队列又有宏任务队列(Macro Task)以及微任务队列(Micro Task)之分 ,在javascript中:
macro-task包括:script(整体代码), setTimeout , setInterval, setImmediate, I/O, UI rendering。
micro-task包括:process.nextTick, Promises , Object.observe, MutationObserver
上面函数的setTimeout就属于宏任务
在js中,事件循环的顺序是从script开始第一次循环,随后全局上下文进入函数调用栈,碰到macro-task就将其交给处理它的模块处理完之后将回调函数放进macro-task的队列之中,碰到micro-task也是将其回调函数放进micro-task的队列之中。直到函数调用栈清空只剩全局执行上下文,然后开始执行所有的micro-task。 当所有可执行的micro-task执行完毕之后。循环再次执行macro-task中的一个任务队列 ,执行完之后再执行所有的micro-task,就这样一直循环。
新闻热点
疑难解答
图片精选