diveDylan / blog

My blog, detail is in the issues list
2 stars 0 forks source link

event loop #7

Open diveDylan opened 5 years ago

diveDylan commented 5 years ago

定义

event loop指的是js的事件运行机制,不同环境node和浏览器对这个的事件循环实现略有出入。

概念

关于event loop就不得不说几个概念: 宏任务和微任务

宏任务

宏任务macrotask,也叫task,包含以下事件:

微任务

微任务microtask,包含一下事件:

event loop的执行机制

  1. js先自上而下执行全局同步代码,这里同步代码也包含new Promiseasync await中的同步代码(起始相当于一个大的宏任务)
  2. 遇到微任务推入第一层微任务队列( 注意,如果在执行microtask的过程中,又产生了microtask,那么会加入到队列的末尾,也会在这个周期被调用执行 ),宏任务推入第一层宏任务队列。
  3. 从头执行第一层微任务队列,执行完所有微任务
  4. 执行第一个宏任务,重复1,2,3,4

代码测试和说明

测试代码输出?便于我们加深理解

const log = (e) => console.log(e)
log('event start')
setTimeout(() => {
  log('setTimeout event 1')
  setTimeout(() => {
    log('setTimeout event 2')

  }, 0)
asy('set asycn 2', 'async event 2')
}, 0);
new Promise(resolve => {
  log('set promise')
  resolve()
}).then(() => {
  log('promise evnet')
  setTimeout(() => {
    log('setTimeout event promise')
  }, 0)
  asy('set async promise', 'promise async')
})
async function asy(e = 'set asycn 1', f = 'async event') {
  log(e)
  await 1
  log(f)
}
asy()

运行这段代码在浏览器中会有如下输出:

event start
set promise
set asycn 1
promise evnet
set async promise
async event
promise async
setTimeout event 1
set asycn 2
async event 2
setTimeout event promise
setTimeout event 2

如果跟你想象的输出一模一样,你已经了解整个event loop执行机制了。当然你也可以往下看看看本文是否有惊喜的地方。

  1. 执行全局代码(可以称他为默认的宏任务),首先输出event start
  2. 遇到第一个宏任务setTimeout,这时候的宏任务队列相当于这样的数组[setTimeout]setTimeout宏任务中生成一个单独的宏任务执行栈
  3. 遇到第一个微任务new Promise,这时候这里面传入函数为同步代码,输出set promise
  4. 到了async await执行环境这里log是同步代码,输出set async 1await后的为微任务,微任务推入 awaitAsy,这时候微任务队列[ Promise, awaitAsy],宏任务[setTimeout]
  5. 执行第一个微任务promise输出promise event,这时候微任务队列[awaitAsy],遇到宏任务setTimeoutPromise推入宏任务队列,宏任务队列[setTimeout, setTimeoutPromise]
  6. 执行Promise微任务环境栈的全局代码 asy,输出set async promise, 将微任务中新的微任务await后部分promiseAsy推入末尾,此时微任务队列为[awaitAsy, promiseAys],宏任务[setTimeout,setTimeoutPromise]
  7. 然后执行微任务awaitAsy,输出async event, 微任务队列为[promiseAys],宏任务[setTimeou,setTimeoutPromiset]
  8. 执行微任务promiseAys,输出promise async,微任务队列为空,执行第一个宏任务
  9. 执行宏任务setTimeout,执行宏任务环境栈的全局代码,输出setTimeout event 1,宏任务队列[]
  10. 遇到宏任务 setTimeout2,推入,宏任务队列[setTimeoutPromise,setTimeout2,]
  11. 执行asy的同步代码输出set asycn 2,将await 部分微任务setTimeoutAsy推入微任务,微任务[setTimeoutAsy],宏任务队列[setTimeoutPromise,setTimeout2]
  12. 执行微任务setTimeoutAsy输出async event 2,然后执行setTimeoutPromise, 输出setTimeout event promise,最后执行最后的宏任务setTimeout2

    总结

    event loop先执行js的全局代码。遇到宏任务先推入宏任务队列,微任务推入微任务队列,微任务执行中遇到微任务,将微任务推入当前微任务队列末尾,宏任务则推入宏任务队列末尾,new Promise中的入参和async awaitawait前部分是同步代码,执行完所有微任务会执行第一个宏任务,按上述执行完这个宏任务的所有微任务,进入下一个宏任务