浏览器中的Event Loop

同步任务和异步任务

同步任务:在主线程上排队的任务,只有上一个任务执行完毕才会执行下一个任务。
异步任务:不进入主线程,而是进入“任务队列”的任务,等任务队列通知主线程,该任务才会进入主线程执行

异步执行的机制

  1. 所有同步任务都在主线程中实行,形成执行栈
  2. 主线程之外还有一个任务队列,只要异步任务有了运行结果,就放入任务队列中,等待主线程执行
  3. 主线程执行完毕之后就会去任务队列中将其中的任务拿到主线程中执行
  4. 主线程不断的重复上述三步

    宏任务和微任务

    以上的事件循环过程是一个宏观的表述,实际上因为异步任务之间并不相同,因此他们的执行优先级也有区别。不同的异步任务被分为两类:微任务(micro task)和宏任务(macro task)。
  1. 宏任务大概包括:
  • setTimeout
  • setInterval
  • requestAnimationFrame (浏览器独有)
  • I/O
  • UI rendering (浏览器独有)
  1. 微任务大概包括:
  • Promise
  • Object.observe
  • MutationObserver

    event loop机制

    v2-61c035f1e5af822631ba1845b6f5829a_1440w.jpg
  1. 执行全局 Script 代码,这些代码中有同步语句或异步语句,遇到同步语句直接执行,异步语句放入宏任务或微任务的队列。
  2. 全局 Script 代码执行完毕后,调用栈 Stack 会清空
  3. 从微任务中取出位于队首的回调任务,放入调用栈 Stack 中执行,执行完成后 微任务队列长度减一
  4. 继续取出位于队首的任务,放入调用栈 Stack 中执行,以此类推,直到把 微任务队列 中的所有任务都执行完毕。注意,如果在执行微任务过程中,又产生了新的微任务,那么会加入到微任务队列的尾部,也会在这个周期被执行
  5. 当 微任务队列 中的所有任务都执行完毕后,此时 微任务队列 为空,调用栈 Stack 也会空
  6. UI rendering的节点,因为这个是由浏览器自行判断决定的,但是只要执行UI rendering,它的节点是在执行完所有的 微任务 之后,下一个 宏任务 之前,紧跟着执行UI render。
  7. 取出宏任务中的队首的任务放入 Stack 中执行
  8. 执行完毕后,调用栈Stack为空
  9. 重复第3-7个步骤