浏览器渲染原理
详细说说浏览器的渲染过程
首先会通过 HTML Parser,来解析 HTML 生成一颗 DOM Tree,然后会解析 CSS 样式,这里主要会格式化样式,标准化样式表,计算每个 DOM 节点的具体样式,格式化样式表就是把用户输入的 css 进行标准化,有一些单位转化,格式转化等,计算每个 DOM 节点的样式会累计他的父节点的东西,把继承和层叠下发的约束一同计算,得到每个节点自己的 style。因为 DOM 树上有些节点并不需要进行渲染,所以会构建一颗 layoutTree,通过前面的 CSSOM 得到节点的位置信息。
在构建了 renderTree 之后,会对一些特殊的节点进行分层,生成 LayerTree,这里进行分层主要是为了减少页面内大面积的频繁出现回流吧。
在完成图层的构建之后,会把每个图层拆成一些很小的绘制指令,然后再按照这些指令的顺序组成一个绘制列表/
渲染进程的主线程会给合成线程发送 commit 消息,把绘制列表提交发送给合成线程,由于用户的页面可能会很大嘛,那么提交过来的绘制列表也会很大,但是用户不会一次看完这么多的内容,那么如果一次性计算完所有的图层内容,就很没有必要,合成线程会对图层进行图块的划分。
在生成了图块之后,合成线程会按照视口附近的图块来优先生成位图,也就是 raster,raster 的目的就是 图块转成位图
在生成位图之后,会生成一个绘制命令,会发送 DrawQuad 命令给浏览器进程。
说说 Canvas 在浏览器中的渲染过程
它的渲染过程和 DOM 渲染有些不同,因为 Canvas 内容的绘制都是通过 JS 来调用 API 实现的,会通过 JSEngine 解析,然后通过 JSBinding 来将 Cavans API 绑定到 Skia 图形操作 API 上,然后调用 OpenGL 的接口。
说说浏览器的滚动为什么会出现白屏?
网页滚动有两种实现,一种滚动是在 compositor 线程执行,另一种是在主线程,在 compositor 线程的滚动,在处理事件的时候,会修改 scroll tree 的状态,以及 transform node,然后直接生成滚动后的 drawQuad。 在主线程的滚动会经过完整的一个生命周期,也就是 从 生成图块、raster 最后到 draw 的完整流程
那么 由于主线程需要执行 js,主线程如果出现了卡顿,那么就会影响到滚动的流畅性,而 compositor 线程的滚动,则会因为没有足够的图块来生成新的位图,而出现渲染不完整的白屏现象。
(追问)为什么拖动浏览器滚动条,出现白屏的概率会加大?
因为浏览器的
(追问)可以怎么解决呢?
可以通过在 chrome://flags 中关闭 threaded-scrolling 线程滚动,来解决,这样采用主线程的滚动就可以避免白屏的问题,但是可能会导致滚动掉帧,因为主线程可能会繁忙,导致滚动被延后执行