图解JS事件循环Event Loop

374 阅读1分钟

事件循环是什么

js是单线程运行的,根据情况执行同步代码和异步代码

同步代码:立即执行的主线程代码,大部分代码都是同步代码

异步代码:比如网络请求、setTimeout定时函数

宏任务&微任务

异步任务分为宏任务、微任务

常见微任务:

  • Promise.then
  • MutaionObserver
  • process.nextTick
  • asnyc/await中await下方被阻塞的代码

常见宏任务:

  • script (可以理解为外层同步代码)
  • setTimeout/setInterval
  • UI rendering/UI事件
  • setImmediate、I/O

图解EventLoop

  • 执行顺序
    1. main Script的代码(无等待的)
    2. 执行微任务,直至微任务队列清空
    3. 微任务队清空后,执行宏任务(宏任务回调中有微任务的时,依旧是清空微任务再执行宏任务)

一段经典的异步代码

async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2() {
    console.log('async2')
}
console.log('script start')
setTimeout(function () {
    console.log('settimeout')
})
async1()
new Promise(function (resolve) {
    console.log('promise1')
    resolve()
}).then(function () {
    console.log('promise2')
})
console.log('script end')
  1. 打印'script start',遇到setTimeout丢入宏任务队列
  2. 执行async1函数,打印'async1 start',执行async2函数,打印‘async2’,后续代码执行遇到阻塞,即被丢入了微任务队列
  3. 执行new Promise函数,打印'promise1',then函数部分丢入微任务队列
  4. 打印'script end'
  5. 开始清空微任务队列,打印'async1 end',打印'promise2'
  6. 开始执行下一个宏任务,打印‘settimeout’

执行顺序:script start、async1 start、async2、promise1、script end、async1 end、promise2、settimeout