事件循环以及浏览器渲染时机

事件循环机制(Event Loop)

我们知道JS是单线程的,这意味着在同一时刻,JS只会处理一件事情,但是我们在平时写前端代码时,总会杂糅着进行「处理事件」、「执行AJAX请求」、「调用API」等各种事情,这就依靠事件循环机制(Event Loop)来处理。主要的进行步骤,能查到的资料有很多,总结就是以下几步:

  1. 事件队列中取出一项「宏任务」进行处理;
  2. 检查「微任务」队列中是否有需要处理的「微任务」
    • 如果有「微任务」,逐一处理
    • 在此期间产生的「微任务」,放入「微任务队列」末尾
  3. 执行 UI 渲染
    • 判断是否需要渲染
      • 渲染只保证浏览器60Hz的刷新频率
      • 并非每次循环都会触发渲染
      • 触发resizescroll等事件
      • 执行css动画
      • 等等
    • 执行requestAnimationFrame
    • 执行IntersectionObserver callback
    • 渲染UI
  4. 如果「宏任务队列」为空,休眠直到一个「宏任务」出现
  5. 回到第一步

宏任务及微任务

哪些事件会触发「宏任务」及「微任务」呢?见下图:

宏任务

产生宏任务的主要来源有:

  1. DOM操作
  2. 监听事件回调(键盘、鼠标事件等)
  3. AJAX请求
  4. 调用浏览器API(如:history.back())
  5. setTimeout/setInterval
  6. 操作IndexDB

已上产生的事件,每次只会执行一件。

微任务

产生微任务的主要来源有:

  1. Promise.then、Promise.catch、Promise.finally
  2. MutationObserver
  3. Object.observe

「微任务队列」中的事件会逐一执行。

requestAnimationFrame

requestAnimationFrame的回调机制在不同的浏览器上不同,在EageSafari上会在UI渲染之后调用,在ChromeFirefox上会在UI渲染之前调用。

结语

已上记录了一些关于事件循环(Event Loop)以及浏览器渲染时机的知识点,关于事件循环(Event Loop)能搜索到很多的题目去练习,了解原理后可以结合题目作更深的理解。


参考

深入探究 eventloop 与浏览器渲染的时序问题

webappapis

【前端】事件原理讲解

事件循环:微任务和宏任务