前言
大家好,我是抹茶。
前些天被问了一个问题“如何理解浏览器的空闲时间”,下意识脱口而出,那就是浏览器不忙的时候呀!
真的是呵呵了,浏览器啥时候不忙?根据已知的关于浏览器的事件循环内容,浏览器可是一直在忙的呀。所以这个问题应该怎么理解和回答呢?
抹茶查阅了相关的资料,有了自己的理解,希望也能帮助到屏幕前的你。
空闲的范围框定
已知浏览器的事件循环的特点就是源源不断循环执行创建的任务,故而如果从浏览器打开tab渲染页面再到关闭tab的过程去很粗略的说浏览器的空闲时间是非常难衡量的,所以我们应该要用一个更细的颗粒度去框定范围,回归到浏览器,也就是具体到每一帧的范围去衡量空闲时间。
在每一帧中浏览器的空闲时间
浏览器的空闲时间通常是按照帧来计算的。在浏览器中,帧是渲染过程中的一个基本单位,每一帧包括了从处理用户输入、执行JavaScript、样式计算、布局、绘制到合成等一系列步骤。
每一帧都有一定的时间预算,这个预算是由显示器的刷新率决定的。
以下是关于按帧计算空闲时间的几个特点:
-
帧时间预算:对于60Hz的显示器,每一帧大约有16.67 (1000 ms/60 ≈ 16.67) 毫秒的时间来完成所有必要的渲染任务。帧率越高,每一帧的时间预算就越少。例如,120Hz的显示器每一帧的时间预算大约是8.33毫秒。这个时间预算是固定的,而任务执行的时间是可变的。
-
空闲时间:如果在一帧的时间预算内,浏览器完成了所有必需的任务,并且还有剩余时间,这段剩余时间就是空闲时间。在这段时间内,浏览器可以执行一些低优先级的任务,如
requestIdleCallback中注册的任务。 -
任务调度:浏览器会优先处理与当前帧直接相关的任务。只有在这些任务完成后,如果有空闲时间,浏览器才会考虑执行其他低优先级的任务。
-
帧与帧之间的空闲时间:空闲时间是在一帧的末尾计算得出的,它可能出现在一帧结束和下一帧开始之间的时间段内。如果浏览器在这段时间内没有其他紧急任务需要处理,那么它就可以利用这段空闲时间。
-
动态变化:空闲时间是动态变化的,它取决于每一帧实际执行的任务量和时间。如果在某帧中任务执行时间较长,那么该帧的空闲时间可能会非常短,甚至没有空闲时间。
通过performance面板查看浏览器的空闲时间
渲染过程整体的空闲时间
我们通过“Record and Reload”(记录并重新加载)按钮,记录页面从加载到完全渲染的整个过程,同时自动重新加载页面。
如下图的idle部分就是在整个页面加载到完全渲染的过程中,浏览器的空闲时间。
没有空闲时间的情况
"Partially Presented Frame"(部分呈现的帧)
在显示黄色的帧,hover过去,显示"Partially Presented Frame"(部分呈现的帧),即该帧在浏览器尝试渲染时,没有完全准备好所有内容,因此只呈现了部分内容的情况。这通常发生在帧的渲染时间超过了理想的时间预算(通常是16.67毫秒,对应于60帧/秒的刷新率),导致浏览器不得不展示不完整的帧。
如下图,在该帧时候,浏览器忙着密密麻麻的任务。
"Dropped Frame"(掉帧)
在显示红色的帧,hover过去,显示"Dropped Frame"(掉帧),即该帧在浏览器尝试渲染动画或视频时,由于各种原因未能按预期绘制一帧的情况。掉帧会导致动画看起来不流畅,影响用户体验。
如下图,在掉帧的片段,有4个animation,光是样式计算花了11.30ms,留给浏览器忙其他事情的时间不多了,从而导致了掉帧。
总结
- 浏览器的空闲时间是针对渲染的每一帧而言,在页面初始化渲染过程中的idle时间就是,每一帧的空闲时间总和。
- 每一帧的时间是跟屏幕的刷新频率有关,60hz的就是(1000 ms/60 ≈ 16.67),120hz的就是(1000 ms/120 ≈ 8.33)
- 不是每一帧都会有空闲时间,如果当前帧有空闲时间(浏览器忙完优先级高的任务后还有结余),可以通过
requestIdleCallback执行其他任务。 - 可能会有
Partially Presented Frame(部分呈现的帧)和Dropped Frame(掉帧)的情况,浏览器是真的一点空闲时间都没有,要完成主要任务都已经超时。