Skip to content

事件循环

为什么需要事件循环? JS 主要用途是用来操作 DOM,如果 JS 有两个线程同时操作一个 DOM ,就会导致浏览器无法判断执行哪一个。为了避免产生这种问题,JS 必须是单线程,且未来也不会改变。

循环机制

  1. 所有任务都在主线程上执行,形成执行栈
  2. 当主线程执行栈为空时,检查事件队列是否为空,不为空则执行3
  3. 将任务队列首部压入执行栈
  4. 执行任务
  5. 重复2-4

同步任务与异步任务

  • 同步任务:指在主线程上排队执行的任务
  • 异步任务:指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。异步任务分为宏任务与微任务,不同的任务会进入不同的任务队列,并等待 Event loop 依次压入执行栈中执行
    • 常见的宏任务:setTimeout/setInterval、UI渲染、I/O、script、setImmediate(nodejs)
    • 常见的微任务:Promise、process.nextTick(nodejs)、MutaionObserver

Event loop

  1. 执行完主线程的任务,检查微任务队列
  2. 取出微任务队列中的任务,并全部执行完。执行过程中如果又产生了微任务,则添加到本次队列末尾执行继续执行
  3. 取出宏任务第一个任务执行,执行完毕检查微任务队列
  4. 重复2-3

注意 Promise 本身是宏任务,then 和 catch 才是微任务 Nodejs 与 浏览器的执行机制有些微差别

js
const p1 = () => {
  return new Promise(reslove => {
    console.log('p1')
    reslove()
  })
}

const p2 = new Promise(reslove => {
  console.log('p2')
  reslove()
})

p1().then(() => {
  const p3 = new Promise(reslove => {
    console.log('p3')
    reslove()
  })
  p3.then(() => {
    console.log('p3 then')
  })
})

p2.then(() => {
  console.log('p2 then')
})
// p1, p2, p3, p2 then, p3 then