Eventloop

143 阅读3分钟
当我们执行js代码的时候,其实就是将我们的代码放到执行栈中执行,但是遇到异步代码的时候就会以另外一种方式进行。
JavaScript在代码运行到异步代码的时候会根据不同的异步,将代码放到对应的Task里面去
JavaScript一旦执行完执行栈里面的代码之后,Event Loop就会从task队列中拿出需要执行的代码并放入到执行栈中执行代码。
其中Task任务分为二种 microtask(微任务),macrotask(宏任务)
在 ES6 规范中,microtask 称为 jobs,macrotask 称为 task
  • microtask(微任务)process.nextTick、Promise、MutationObserver 等
  • macrotask(宏任务)setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作等。
Event Loop 过程解析
<script>
function func(num) { return function () { console.log(num) };}setTimeout(func(1));async function async3() { await async4(); console.log(8)}async function async4() { console.log(5)}async3();function func2() { console.log(2); async function async1() { await async2(); console.log(9) } async function async2() { console.log(5) } async1(); setTimeout(func(4))}setTimeout(func2);setTimeout(func(3));new Promise(resolve => { console.log('Promise'); resolve()}) .then(() => console.log(6)) .then(() => console.log(7));console.log(0);
</script>
宏任务是一个一个的执行代码的;
微任务是将所有的任务执行完成之后在执行后面的代码的,
哪怕是在微任务阶段添加的微任务也会在当前阶段执行。
  • 首先第一步将script标签放到宏任务队列中,之后将script标签放入执行栈中
[td]
宏任务macrotask微任务microtask执行栈
script标签script标签
  • 执行script标签里面的代码,逐行解析代码。并且将异步代码放到对应的Task中
[td]
宏任务macrotask微任务microtask执行栈
第一个 setTimeout.then(6)async4()
第二个 setTimeoutnew Promise
第三个 setTimeoutconsole.log(0)
  • 首先第一步遇到第一个 setTimeout,将定时器放到宏任务中;
  • 第二步遇到async3() 。执行async3代码,然后调用async4(),运行里面的代码输出5,因为async3使用了async await 所以输出完成5之后await async4()会返回一个Promise,并且后面的代码会在Promise中执行。
async
function
async3
(
)
{
await
async4
(
)
;
console
.
log
(
8
)
}
async
function
async4
(
)
{
console
.
log
(
5
)
}
async3
(
)
;
// 转换
new
Promise
(
resolve
[backcolor=rgba(255, 255, 255, 0.498039)]=>
{
console
.
log
(
5
)
resolve
(
)
}
)
.
then
(
(
)
[backcolor=rgba(255, 255, 255, 0.498039)]=>
{
console
.
log
(
8
)
}
)
// 上述代码转换之后就是这样 , 并且会在当前微任务结束之后在放入微任务队列
// new Promise里面的代码是同步执行的,如果遇到异步在调用Event Loop
  • 下一步开始执行微任务,首先执行async3()里面返回的Promise.then()打印8。然后执行下一个微任务6
输出6之后返回一个新的Promise对象,这时候微任务里面又多了一个任务,这个时候会先执行微任务,不会执行宏任务。要等到所有的微任务全部执行完成之后才会执行宏任务。
[td]
宏任务macrotask微任务microtask执行栈
第一个 setTimeout.then(7)console.log(6)
第二个 setTimeout
第三个 setTimeout
微任务执行完成之后await放入微任务队列
[td]
宏任务macrotask微任务microtask执行栈
第一个 setTimeout.then(8)console.log(7)
第二个 setTimeout
第三个 setTimeout
[td]
宏任务macrotask微任务microtask执行栈
第一个 setTimeoutconsole.log(8)
第二个 setTimeout
第三个 setTimeout
  • 下一步微任务已经都执行完成了,所以开始执行宏任务,并且在调用async1()方法的时候又创建了一个宏任务和一个await
[td]
宏任务macrotask微任务microtask执行栈
打印4的setTimeoutfunc(1)
func2()
async1()
func(3)
微任务执行完成之后放入await;
[td]
宏任务macrotask微任务microtask执行栈
打印4的setTimeoutawait async2()的的Promise.then()
执行宏任务阶段,会将宏任务里面的代码推到执行栈里面执行
  • 执行完成之后开始执行微任务
[td]
宏任务macrotask微任务microtask执行栈
打印4的setTimeoutconsole.log(9)
  • 微任务执行完成之后执行宏任务
[td]
宏任务macrotask微任务microtask执行栈
console.log(4)