当前位置: 首页 > 科技观察

如果你会使用Performance工具,你就能深入理解EventLoop

时间:2023-03-16 22:28:37 科技观察

网页加载完成后,浏览器会解析html,执行js,渲染css。这些任务都是在事件循环中完成的。了解了EventLoop之后,就可以了解网页运行的流程了。然而,很多人对EventLoop的理解仅仅停留在概念层面,并没有看到真正的EventLoop是什么样的。事实上,您可以在性能工具中看到它。今天我们来看一下:首先,我们需要一个网页。这里我使用react使用的网页来测试fiber:https://claudiopro.github.io/react-fiber-vs-stack-demo/fiber.html在Performance面板点击reload记录3s的数据:Main部分是网页的主线程,也就是执行EventLoop的部分:这个区域包含了所有的任务执行流程,以及每一个任务的调用栈,因为它看起来像一团燃烧的火焰,所以也被称为火焰图。将鼠标拖到要看的部分,向下拖动可放大该区域:左右拖动可调整查看位置:显示的信息有多种颜色,这些颜色代表不同的含义:灰色代表宏任务任务:蓝色是html的解析,橙色是浏览器内部的JS:紫色是样式的reflow和repaint,绿色部分是渲染:其余颜色是用户JS的执行,而那些无法区分。如何从Performance看EventLoop的执行过程?一起来看看:你会发现每隔一段时间就会有这样一个任务:放大是这样的:执行AnimationFrame的回调,然后执行回流重绘,最后执行渲染。此任务每16.7毫秒执行一次:这就是在网页中执行渲染的方式。所以requestAnimationFrame的回调是在渲染之前执行的,rAF和渲染构成一个宏任务。有时掉帧卡顿的原因是因为阻塞渲染宏任务的执行:(在Performance中,宽度代表时间,如果超过200ms,则认为是LongTask,会被标记为红色)。我们做性能分析,就是找到这些LongTasks,然后进行优化。那么除了rAF和rendering,还有哪些宏任务呢?看分析结果:可以看到requestIdleCallback的回调是一个宏任务:垃圾回收GC是一个宏任务:requestAnimationFrame的回调是一个宏任务:html中直接执行的脚本也是一个宏任务:这些需要记录吗?不需要,用性能工具查一下就可以了。微任务是如何执行的?可以看出,微任务只是任务的一部分,所有的微任务都会在宏任务执行完毕后执行。这就是这个网页的EventLoop执行过程。当你熟悉了这些之后,看到下面的火焰图就可以分析出一些东西了:中间宽大的红色标记就是LongTask,它是性能优化的主要目标。一些狭窄的周期性任务是requestAnimationFrame回调和回流、重绘和渲染。较长的调用栈一般都是递归的,递归的层数特别多。当你展开它时,它还可以显示完整的代码运行过程:而如果你断点调试,你只能看到其中一个调用堆栈,这是比调试器断点调试更适合用性能工具分析代码流的地方。在阅读源码的时候,也可以通过Performance查看执行过程的全貌,进而调试一些具体的过程。综上所述,Performance工具可以看到网页的EventLoop是如何工作的。不同的颜色代表不同的含义:灰色:task橙色:浏览器内部的JS蓝色:htmlparse紫色:reflow、repaint绿色:rendering其余颜色是用户自己的JS。宽度代表执行时间。如果超过200ms,则认为任务是长任务,需要优化。长度代表调用栈的深度,一般很长的都有递归。你可以用Performance工具分析很多东西:rAF回调和reflow、repaint、rendering构成一个宏任务,每16.7ms执行一次。rAF回调、rIC回调、GC、html中的脚本等都是宏任务。任务执行完毕后,浏览器会执行所有的微任务,即Performance的runAllMicroTasks部分可以看到代码执行的全貌,而断点调试的调用栈只能看到一个进程。所以在调试代码的时候,可以结合Performance和Debugger。总之,如果你知道如何使用Performance工具,你就可以深入理解EventLoop,理清网页执行的整个过程。