当我们打开一个网页的时候,我们的代码一般以为是从上至下依次执行每行代码。
实际上则不然,看下下面的例子
<script>
setTimeout(function(){
console.log('定时器开始啦')
});
new Promise(function(resolve){
console.log('马上执行for循环啦');
for(var i = 0; i < 10000; i++){
i == 99 && resolve();
}
}).then(function(){
console.log('执行then函数啦')
});
console.log('代码执行结束');
</script>
如果按照从上至下的顺序执行的话那么结果就是
定时器开始了
马上执行for循环啦
执行then函数了
代码执行结束
实际上在控制台上输出为
马上执行for循环
代码执行结束
执行then函数啦
定时器开始了
这是什么原因呢,让我们来分析一下
- 这段代码作为宏任务,进入主线程。
- 先遇到setTimeout,那么将其回调函数注册后分发到宏任务Event Queue。(注册过程与上同,下文不再描述)
- 接下来遇到了Promise,new Promise立即执行,then函数分发到微任务Event Queue。
- 遇到console.log(),立即执行。
- 好啦,整体代码script作为第一个宏任务执行结束,看看有哪些微任务?我们发现了then在微任务Event Queue里面,执行。
- ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务EventQueue中setTimeout对应的回调函数,立即执行。
- 结束。