如何理解浏览器的空闲时间

1,215 阅读4分钟

前言

大家好,我是抹茶。

前些天被问了一个问题“如何理解浏览器的空闲时间”,下意识脱口而出,那就是浏览器不忙的时候呀!

真的是呵呵了,浏览器啥时候不忙?根据已知的关于浏览器的事件循环内容,浏览器可是一直在忙的呀。所以这个问题应该怎么理解和回答呢?

抹茶查阅了相关的资料,有了自己的理解,希望也能帮助到屏幕前的你。

空闲的范围框定

已知浏览器的事件循环的特点就是源源不断循环执行创建的任务,故而如果从浏览器打开tab渲染页面再到关闭tab的过程去很粗略的说浏览器的空闲时间是非常难衡量的,所以我们应该要用一个更细的颗粒度去框定范围,回归到浏览器,也就是具体到每一帧的范围去衡量空闲时间。

在每一帧中浏览器的空闲时间

浏览器的空闲时间通常是按照帧来计算的。在浏览器中,帧是渲染过程中的一个基本单位,每一帧包括了从处理用户输入、执行JavaScript、样式计算、布局、绘制到合成等一系列步骤。

浏览器每一帧在干的事情.png

每一帧都有一定的时间预算,这个预算是由显示器的刷新率决定的。

以下是关于按帧计算空闲时间的几个特点:

  • 帧时间预算:对于60Hz的显示器,每一帧大约有16.67 (1000 ms/60 ≈ 16.67) 毫秒的时间来完成所有必要的渲染任务。帧率越高,每一帧的时间预算就越少。例如,120Hz的显示器每一帧的时间预算大约是8.33毫秒。这个时间预算是固定的,而任务执行的时间是可变的。

  • 空闲时间:如果在一帧的时间预算内,浏览器完成了所有必需的任务,并且还有剩余时间,这段剩余时间就是空闲时间。在这段时间内,浏览器可以执行一些低优先级的任务,如requestIdleCallback中注册的任务。

  • 任务调度:浏览器会优先处理与当前帧直接相关的任务。只有在这些任务完成后,如果有空闲时间,浏览器才会考虑执行其他低优先级的任务。

  • 帧与帧之间的空闲时间:空闲时间是在一帧的末尾计算得出的,它可能出现在一帧结束和下一帧开始之间的时间段内。如果浏览器在这段时间内没有其他紧急任务需要处理,那么它就可以利用这段空闲时间。

  • 动态变化:空闲时间是动态变化的,它取决于每一帧实际执行的任务量和时间。如果在某帧中任务执行时间较长,那么该帧的空闲时间可能会非常短,甚至没有空闲时间。

通过performance面板查看浏览器的空闲时间

渲染过程整体的空闲时间

我们通过“Record and Reload”(记录并重新加载)按钮,记录页面从加载到完全渲染的整个过程,同时自动重新加载页面。 image.png

如下图的idle部分就是在整个页面加载到完全渲染的过程中,浏览器的空闲时间

image.png

没有空闲时间的情况

"Partially Presented Frame"(部分呈现的帧)

显示黄色的帧,hover过去,显示"Partially Presented Frame"(部分呈现的帧),即该帧在浏览器尝试渲染时,没有完全准备好所有内容,因此只呈现了部分内容的情况。这通常发生在帧的渲染时间超过了理想的时间预算(通常是16.67毫秒,对应于60帧/秒的刷新率),导致浏览器不得不展示不完整的帧。

如下图,在该帧时候,浏览器忙着密密麻麻的任务。

image.png

"Dropped Frame"(掉帧)

显示红色的帧,hover过去,显示"Dropped Frame"(掉帧),即该帧在浏览器尝试渲染动画或视频时,由于各种原因未能按预期绘制一帧的情况。掉帧会导致动画看起来不流畅,影响用户体验。

如下图,在掉帧的片段,有4个animation,光是样式计算花了11.30ms,留给浏览器忙其他事情的时间不多了,从而导致了掉帧。

image.png

image.png

总结

  • 浏览器的空闲时间是针对渲染的每一帧而言,在页面初始化渲染过程中的idle时间就是,每一帧的空闲时间总和。
  • 每一帧的时间是跟屏幕的刷新频率有关,60hz的就是(1000 ms/60 ≈ 16.67),120hz的就是(1000 ms/120 ≈ 8.33)
  • 不是每一帧都会有空闲时间,如果当前帧有空闲时间(浏览器忙完优先级高的任务后还有结余),可以通过requestIdleCallback执行其他任务。
  • 可能会有Partially Presented Frame(部分呈现的帧)Dropped Frame(掉帧)的情况,浏览器是真的一点空闲时间都没有,要完成主要任务都已经超时。