事件循环以及浏览器渲染时机
事件循环机制(Event Loop)
我们知道JS是单线程的,这意味着在同一时刻,JS只会处理一件事情,但是我们在平时写前端代码时,总会杂糅着进行「处理事件」、「执行AJAX请求」、「调用API」等各种事情,这就依靠事件循环机制(Event Loop)来处理。主要的进行步骤,能查到的资料有很多,总结就是以下几步:
- 从事件队列中取出一项「宏任务」进行处理;
- 检查「微任务」队列中是否有需要处理的「微任务」
- 如果有「微任务」,逐一处理
- 在此期间产生的「微任务」,放入「微任务队列」末尾
- 执行 UI 渲染
- 判断是否需要渲染
- 渲染只保证浏览器60Hz的刷新频率
- 并非每次循环都会触发渲染
- 触发
resize
、scroll
等事件 - 执行css动画
- 等等
- 执行
requestAnimationFrame
- 执行
IntersectionObserver callback
- 渲染UI
- 判断是否需要渲染
- 如果「宏任务队列」为空,休眠直到一个「宏任务」出现
- 回到第一步
宏任务及微任务
哪些事件会触发「宏任务」及「微任务」呢?见下图:
宏任务
产生宏任务的主要来源有:
- DOM操作
- 监听事件回调(键盘、鼠标事件等)
- AJAX请求
- 调用浏览器API(如:history.back())
- setTimeout/setInterval
- 操作IndexDB
已上产生的事件,每次只会执行一件。
微任务
产生微任务的主要来源有:
- Promise.then、Promise.catch、Promise.finally
- MutationObserver
- Object.observe
「微任务队列」中的事件会逐一执行。
requestAnimationFrame
requestAnimationFrame的回调机制在不同的浏览器上不同,在Eage
和Safari
上会在UI渲染之后调用,在Chrome
和Firefox
上会在UI渲染之前调用。
结语
已上记录了一些关于事件循环(Event Loop)以及浏览器渲染时机的知识点,关于事件循环(Event Loop)能搜索到很多的题目去练习,了解原理后可以结合题目作更深的理解。