如果在window环境下,会根据硬件条件决定是否渲染,比如刷新率,页面性能,页面是否在后台,不过渲染会定期出现,避免页面卡顿。值得注意的是,正常的刷新率为60hz,大概是每秒60帧,大约16.7ms每帧,如果当前浏览器环境不支持这个刷新率的话,会自动降为30hz,而不是丢帧。而李兰其在后台的时候,聪明的浏览器会将这个渲染时机降为每秒4帧甚至更低,事件循环也会减少(这就是为什么我们可以用setInterval来判断时候能打开其他app的判断依据的原因)。如果能渲染的话会设置hasARenderingOpportunity为true。
除此之外,还会在触发resize、scroll、建立媒体查询、运行css动画等,也就是说浏览器几乎大部分用户操作都发生在事件循环中,更具体点是事件循环中的ui render部分。之后会进行requestAnimationFrame和IntersectionObserver的触发,再之后是ui渲染
如果下面条件都成立,那么执行空闲阶段算法,对于开发者来说就是调用window.requestIdleCallback方法
在window环境下
event loop中没有活跃的Task
微任务队列为空
hasARenderingOpportunity为false
借鉴网上的一张图来粗略表示下整个流程
小结上面就是整个事件循环的流程,浏览器就是按照这个规则一遍遍的执行,而我们要做的就是了解并适应这个规则,让浏览器渲染出性能更高的页面。
比如:
非首屏相关性能打点可以放到idle callback中执行,减少对页面性能的损耗
微任务中递归添加微任务会导致页面卡死,而不是随着事件循环一轮轮的执行
更新元素布局的最好时机是在requestAnimateFrame中
尽量避免频繁获取元素布局信息,因为这会触发强制layout(哪些属性会导致强制layout?),影响页面性能
事件循环有多个任务队列,他们互不冲突,但是用户交互相关的优先级更高
resize、scroll等会伴随事件循环中ui渲染触发,而不是根据我们的滚动触发,换句话说,这些操作自带节流
等等,欢迎补充