宏任务和微任务(面试题)
1 | <script> |
1 | Start |
事件循环流程分析如下:
- 整体
script
作为第一个宏任务进入主线程,遇到console.log,输出Start
。 - 遇到
setTimeout
,其回调函数被分发到宏任务Event Queue中。 - 遇到
Promise
,new Promise直接执行,输出Promise。then被分发到微任务Event Queue中。 - 遇到console.log,立即执行,输出
End
。 - 整体代码
script
作为第一个宏任务执行结束,看看有哪些微任务?我们发现了then
在微任务Event Queue里面,执行 - ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event Queue中
setTimeout
对应的回调函数,立即执行。 - 所以代码结束。
1 | async function async1() { |
第一轮事件循环流程分析如下:
整体script作为第一个宏任务进入主线程,async1(),和async12()函数申明,但并没有执行,遇到
console.log
输出script start
。继续向下执行,遇到
setTimeout
,把它的回调函数放入宏任务Event Queue。(ps:暂且叫他setTimeout1)宏任务 微任务 setTimeout1 继续向下执行,又遇到一个
setTimeout
,继续将他放入宏任务Event Queue。(ps:暂且叫他setTimeout2)宏任务 微任务 setTimeout1 setTimeout2 遇到执行async1(), 进入
async
的执行上下文之后,遇到console.log
输出async1 start
然后遇到await async2(),由于
()
的优先级高,所有立即执行async2()
,进入async2()
的执行上下文。看到
console.log
输出async2
,之后没有返回值,结束函数,返回undefined,返回async1
的执行上下文的await undefined,由于async
函数使用await
后得语句会被放入一个回调函数中,所以把下面的放入微任务Event Queue中。宏任务 微任务 setTimeout1 async1 => awati 后面的语句 setTimeout2 结束
async1()
遇到Promise
,Promise本身是同步的立即执行函数 new Promise直接执行,输出Promise2
。then
后面的函数被分发到微任务Event Queue中宏任务 微任务 setTimeout1 async1 => awati 后面的语句 setTimeout2 new Promise() => 后的then 执行完
Promise()
,遇到console.log
,输出script end
,这里一个宏任务代码块执行完毕。在主线程执行的过程中,事件触发线程一直在监听着异步事件, 当主线程空闲下来后,若微任务队列中有任务未执行,执行的事件队列(Event Queue)中有微任务,遇到
new Promise()
后面的回调函数,执行代码,输出then3
。看到
async1
中await
后面的回调函数,执行代码,输出async1 end
(注意:如果俩个微任务的优先级相同那么任务队列自上而下执行,但是promise的优先级高于async,所以先执行promise后面的回调函数)自此,第一轮事件循环正式结束,这一轮的结果是输出:
1
script start => async1 start => async2 => promise2 => script end => then3 => async1 end
宏任务 微任务 setTimeout1 setTimeout2 那么第二轮时间循环从setTimeout宏任务开始:
setTimeout和setInterval的运行机制是,将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop时重新判断。因为setTimeout1有200ms的延时,并没到达指定时间,所以先执行setTimeout2这个宏任务
进入到setTimeout2,遇到
console.log
首先输出setTimeout2
;遇到
Promise
,Promise本身是同步的立即执行函数new Promise直接执行。then
后面的函数被分发到微任务Event Queue中宏任务 微任务 setTimeout1 new Promise() => 后的then1 再次遇到
Promise
,Promise本身是同步的立即执行函数new Promise直接执行输出promise1
。then
后面的函数被分发到微任务Event Queue中宏任务 微任务 setTimeout1 new Promise() => 后的then1 空 new Promise() => 后的then2 主线程执行执行空闲,开始执行微任务队列中依次输出
then1
和then2
。第二轮事件循环正式结束。第二轮依次输出
1
promise1 => then1 => then2
现在任务队列中只有个延时200ms的setTimeout1,在到达200ms后执行setTimeout的回调函数输出
setTimeout1
时间循环结束
整段代码,完整的输出为
1
script start => async1 start => async2 => promise2 => script end => then3 => async1 end => promise1 => then1 => then2 => setTimeout1
总结
- 在执行栈中执行一个宏任务。
- 在执行过程中遇到微任务和宏任务,分别添加到微任务队列和宏任务队列中去。
- 当前宏任务执行完毕,立即执行微任务队列中的任务(**微任务存在优先级,优先级高的先执行(**promise的优先级高于async**)**)。
- 当前微任务队列中的任务执行完毕,检查渲染,GUI线程接管渲染。
- 继续执行下一个宏任务从事件队列中取。