【精简版】浏览器渲染机制(完整流程概述)(上)

简介: 【精简版】浏览器渲染机制(完整流程概述)(上)

背景


资料:docs.google.com/presentatio…

我们作为工程师,一名开发者,我认为时刻保持好奇心是一件很重要的事情,前端工程师们,不知你们是否好奇过 我们写出的代码究竟是如何变成屏幕上五彩斑斓的像素点的


本文就是来解决上面的这个问题的。


本文目的


但是,浏览器的渲染机制其实是一个很大的研究课题,过去的一个月我做了很多研究,找了很多资料,废了很多心血,越发觉得其中的很多细节可以消耗我很多很多时间,我也仅仅是了解到皮毛,文章中也会有我个人的理解,也可能存在错误,如果有大佬看到,也希望多多指导和批评,我也会积极采纳。


本文的目的是用通俗的语言,为大家介绍浏览器渲染的完整过程,并不会对每一步进行细致深入的讲解,(即让大家读懂是我最大的目标)。所以,阅读本文你可以得到什么呢:


  • 浏览器渲染的大致流程
  • 得到一个和别人喝咖啡的时候的聊天话题
  • 和我变成朋友(这是最关键的一点是吧,嘿嘿)


勘误


流程图 中的主进程 -> 主线程。(画图的时候没注意,抱歉。。。老朽在此认罪)


goal渲染的目标


首先,本文名称是浏览器渲染机制,那我们第一步就是要了解,浏览器渲染的目标是什么?


网络异常,图片无法展示
|


看上图,我们首先要了解一个content的概念,content指的是网页中这个区域,上面的标签栏,地址栏都不属于content。


网络异常,图片无法展示
|


所以,我们知道了整个渲染过程我们的输入是前端的代码,输出是content区域的像素点。好,这样我们渲染的目标就很明确了,即:把前端写出的代码转换成网页content区域的像素点!


下面,我们开始,为中间这个RENDER管道,一点一点的加上内容,让它丰满起来。


Blink(浏览器渲染机制之主线程做了啥)


DOM


往后的阅读,希望大家跟着我的思路,跟着思考,我会解释的很通俗,不要中途离开,拉钩哈。(拉完勾之后,说好的阅读完就要阅读完,一句话,一个字没有读,都不是阅读完~ )


DOM阶段介绍


首先,大家去想,我们的输入是code,但是中间过程的处理是,需要一个数据结构的,

你这个输入的code说白了只是冰冷的字符串,我们第一步要做的肯定是把它转换成有温度的数据结构。


<div>
  <p> hello </p>
  <p> world </p>
</div>

所以,这个数据结构应该是什么样的呢?我们知道,其实html标签其实是可以嵌套的层次结构,比如很常见的一个div里丢了两个p标签。所以,用一个树形结构,对其进行表示再合适不过了。


网络异常,图片无法展示
|


这个树形结构也就如上图所示,他也有一个名字:DOM(Document Object Model)。

那么DOM有什么用呢:


  • DOM是页面的内部表示
  • DOM也为js提供了查询和修改的api接口


DOM阶段总结


这一步,浏览器干了什么事情,解析了html,把html转化成了DOM。

输入:html代码

输出:DOM

目前流程图:


网络异常,图片无法展示
|


STYLE

STYLE阶段介绍


大家现在想一想,现在我们有了DOM,但是这个DOM只是html转化出来的数据结构,上面是没有样式信息的,而我们要得到的数据结构一定是带有样式信息并且能表示标签嵌套层级的数据结构。所以我们在Style这一步,目的是为了可以得到能与DOM有效结合的css结构!!


这一步和DOM的意思也差不多,我们会把css代码转换成CSSOM。所以我们模仿一下前面DOM的话,那么CSSOM有什么作用呢?


  • 能表示css结构的层级
  • 为js提供可以操作css的API,允许用户动态的读取和修改css样式。


下一步,浏览器会再计算出computedStyle,DOM树中的每一个节点都有对应的computedStyle。


STYLE阶段总结


这一步,浏览器干了什么事情,把css解析,转化成了CSSOM,又转换成了和DOM节点一一对应的computedStyle。


输入:css

输出:computedStyle

目前流程图:


网络异常,图片无法展示
|


LAYOUT

LAYOUT阶段介绍


首先,我们回顾一下,我们前面的操作得到了啥,我们得到了DOM,它可以表示标签的嵌套结构,又得到了computedStyle,它存储着样式信息并可以和DOM节点一一对应。于是,我们想法就很简单,把DOM和computedStyle结合起来。于是乎,就有了LAYOUT这个阶段。


layout布局算法的输入就是DOM和computedStyle。


这一步主要就是确定元素的几何形状,坐标和尺寸。其中有以下几点要处理:


  • 【块流】最简单的情况下,布局按dom的顺序,垂直的排列一个有一个块,也叫块流(block flow)
  • 【行内流】还有文本和行内元素比如span,会在一行从左到右流动,叫做行内流,inline-flow。
  • 【字体】布局也要计算字体。(使用HarfBuzz的文本形状库)
  • 【包围矩形】布局可以为一个元素计算多种类型的边界矩形。 例如,当存在溢出时,布局将计算边框框的矩形和布局溢出矩形。如果节点的溢出是可滚动的,布局还计算滚动边界并为滚动条保留空间。最常见的可滚动DOM节点是document节点本身(dom树的根)。
  • 【复杂布局】比如表格,或者由内容包围的浮动元素


网络异常,图片无法展示
|


最后这个阶段会生成Layout Tree,这个Layout Tree与DOM相关联,但是不是一一对应的,比如:


  • 一个容器里面有了 div和span,span是行内元素,div是块级元素,于是,为了保证容器里面只有块级盒子,所以会在span的布局对象外面包裹一层匿名的块级盒子。这就是一个LayoutObject没有对应的DOM节点的情况。(如上图anonymous LayoutBlock)
  • 以及如果一个盒子的计算属性中的display属性是none,那么它也没有对应的LayoutObject。


LAYOUT阶段总结


这一步,我们干了什么事情,我们拿到了上一步的结果(DOM和computedStyle),通过布局算法,将两者进行了结合,我们得到了含有样式信息,布局信息的layout tree。但是注意这个layout tree和DOM不是一一对应的。


输入:DOM,computedStyle


输出:layout tree

目前流程图:


网络异常,图片无法展示
|


paintlayer tree


前面我们得到了Layout Tree,但是现在有一个问题,现在这个东西只能无脑的让文档流靠后的元素覆盖前面的元素。然而浏览器还有个层叠上下文就是决定元素间相互覆盖关系(比如z-index)的东西。这使得文档流中位置靠前位置的元素有可能覆盖靠后的元素。

于是PaintLayer Tree诞生了!!!PaintLayer 这棵树主要用来实现层叠上下文,以保证dom重叠时也能用正确的顺序合成页面,这样才能正确的展示元素的重叠以及半透明元素等等。


我们在此,只需要,为了处理层叠上下文,于是有了paintlayer tree,就ok了。

于是现在的流程图变成了这样:


网络异常,图片无法展示
|


comp.assign

comp.assign阶段介绍


好的,经过前面几个步骤,我们拿到了一个具有样式属性又可以表示嵌套结构的的数据结构了。所以,我们现在可以想一些额外的问题了?


我们的页面是静态的么?是不是有可能经常变动?

所以,如果变动会导致整个渲染过程重新运行一遍,是不是开销巨大?

所以,这个问题是不是要解决? 是的,必须要解决!!!(大喊,并有哭腔)

于是我们引入了图层合成加速的概念。什么是图层合成加速?


  • 图层合成加速是把整个页面按照一定规则划分成多个图层,在渲染的时候,只要操作必要的图层,其他的图层只要参与合成就好了,以这种方式提高了渲染的效率

合成层作用:

  • 合成层的绘制,渲染会交给GPU处理,比CPU更快
  • repaint时,只用repaint自身即可

于是为了页面变动时的性能,我们引入了comp.assign这个阶段,他会把整个页面按照一定规律划分成多个图层。


comp.assign阶段总结


这一步,我们干了什么事情,我们为了页面变动时不重新运行整个渲染的管道,把整个页面拆分成了很多图层。


输入:paintlayer tree/layout tree

输出:GraphicsLayer(图层) Tree

目前流程图:(我们的内容也越来越充实了)


网络异常,图片无法展示
|


Prepaint

Prepaint阶段介绍


在描述属性的层次结构这一块,之前的方式是使用图层树(GraphicsLayer Tree)的方式,如果父图层具有矩阵变换(平移、缩放或者透视)、裁剪或者特效(滤镜等),需要递归的应用到子节点,这在极端情况下会有性能问题。 于是,就有了 属性树这个概念。合成器提供了变换树,裁剪树,特效树等。每个图层都有若干节点id,分别对应不同属性树的矩阵变换节点、裁剪节点和特效节点。 在发生变换的时候,可以直接对这些节点进行操作。


网络异常,图片无法展示
|


Prepaint阶段总结


目的:对这些变换进行单独处理以提高性能。


做了什么:对这些上述变换做了单独处理,构建了 property trees(属性树,注意是trees)

输入:paintlayer tree/layout tree

输出:Property trees

目前流程图:


网络异常,图片无法展示
|


Paint

Paint阶段介绍


paint阶段,我就简单的一笔带过,就是我们去遍历上一阶段结果(即:GraphicsLayers)并把绘制的操作放在一个数据结构里面(DisplayItem)

Paint阶段也是 blink和cc(合成器组件)对接的阶段,会对DisplayItem List再处理为 cc:layer list 并和prepaint阶段产生的Property trees提交给 合成器线程。


网络异常,图片无法展示
|


在此我引用了官方的流程图,大家可以以此回顾,我们之前做了什么。


from layout
  |
  v
+------------------------------+
| LayoutObject/PaintLayer tree |-----------+
+------------------------------+           |
  |                                        |
  | PaintLayerCompositor::UpdateIfNeeded() |
  |   CompositingInputsUpdater::Update()   |
  |   CompositingLayerAssigner::Assign()   |
  |   GraphicsLayerUpdater::Update()       | PrePaintTreeWalk::Walk()
  |   GraphicsLayerTreeBuilder::Rebuild()  |   PaintPropertyTreeBuider::UpdatePropertiesForSelf()
  v                                        |
+--------------------+                   +------------------+
| GraphicsLayer tree |<------------------|  Property trees  |
+--------------------+                   +------------------+
      |                                    |              |
      |<-----------------------------------+              |
      | LocalFrameView::PaintTree()                       |
      |   LocalFrameView::PaintGraphicsLayerRecursively() |
      |     GraphicsLayer::Paint()                        |
      |       CompositedLayerMapping::PaintContents()     |
      |         PaintLayerPainter::PaintLayerContents()   |
      |           ObjectPainter::Paint()                  |
      v                                                   |
    +---------------------------------+                   |
    | DisplayItemList/PaintChunk list |                   |
    +---------------------------------+                   |
      |                                                   |
      |<--------------------------------------------------+
      | PaintChunksToCcLayer::Convert()                   |
      v                                                   |
+--------------------------------------------------+      |
| GraphicsLayerDisplayItem/ForeignLayerDisplayItem |      |
+--------------------------------------------------+      |
  |                                                       |
  |    LocalFrameView::PushPaintArtifactToCompositor()    |
  |         PaintArtifactCompositor::Update()             |
  +--------------------+       +--------------------------+
                       |       |
                       v       v
        +----------------+  +-----------------------+
        | cc::Layer list |  |   cc property trees   |
        +----------------+  +-----------------------+
                |              |
  +-------------+--------------+
  | to compositor
  v



Paint阶段总结


做了什么:处理GraphicsLayers,把绘制操作放在DisplayItem中。因为Paint阶段也是主线程最后一个步骤,也要与合成器线程对接,所以会把数据再处理为 cc:layer list并和prepaint阶段产生的Property trees(也会处理为cc property trees)提交给 合成器线程。


输入:GraphicsLayer Tree,Property trees

中间产物:DisplayItem List

输出: cc:layer list,cc property trees

目前流程图:(一下子就变大了嘿)


网络异常,图片无法展示
|

相关文章
|
1月前
|
存储 前端开发 开发者
|
25天前
|
缓存 自然语言处理 前端开发
浏览器渲染
【10月更文挑战第28天】浏览器渲染涉及将HTML、CSS和JavaScript代码转换为可视网页,主要步骤包括:解析HTML构建DOM树、解析CSS构建CSSOM树、合并DOM与CSSOM生成渲染树、布局确定元素位置和尺寸、绘制元素到屏幕、合成图层形成最终图像。此过程不断优化以提升性能。
|
1月前
|
前端开发 JavaScript 异构计算
简述浏览器的渲染原理
浏览器渲染原理主要包括以下步骤:1)解析HTML文档生成DOM树;2)解析CSS生成CSSOM树;3)结合DOM与CSSOM生成渲染树;4)布局计算(回流)确定元素大小和位置;5)绘制(Paint)将节点转为图形内容;6)合成(Composite)多层图像。整个过程从文档解析到最终输出完整网页,并通过优化技术提升性能。
|
3月前
|
缓存 网络协议 Linux
在Linux中,当用户在浏览器当中输入⼀个网站,计算机对dns解释经过那些流程?
在Linux中,当用户在浏览器当中输入⼀个网站,计算机对dns解释经过那些流程?
|
4月前
|
安全 iOS开发 MacOS
Dolphin指纹浏览器+IPXProxy代理IP:配置与使用全流程
通过代理IP,用户可以轻松绕过地域限制,访问全球范围内的网站和服务。不过想要同时使用多个代理IP的话,就需要借助指纹浏览器。Dolphin指纹浏览器和IPXProxy代理IP是大家常用的组合,这个组合为用户打造了一个既安全又高效的在线环境。下面是Dolphin指纹浏览器配置IPXProxy代理IP使用步骤,帮助大家更好了解这个组合。
124 3
|
4月前
|
域名解析 Web App开发 缓存
在浏览器上输入一个网址后,发生了什么?/HTTP的工作流程/DNS域名解析过程
在浏览器上输入一个网址后,发生了什么?/HTTP的工作流程/DNS域名解析过程
|
5月前
|
域名解析 存储 缓存
HTTP请求流程概览:浏览器构建请求行含方法、URL和版本;检查缓存;解析IP与端口
【6月更文挑战第23天】 HTTP请求流程概览:浏览器构建请求行含方法、URL和版本;检查缓存;解析IP与端口;TCP连接(HTTP/1.1可能需排队);三次握手;发送请求头与体;服务器处理并返回响应;TCP连接可能关闭或保持;浏览器接收并显示响应,更新缓存。HTTP版本间有差异。
89 5
|
4月前
|
Web App开发
软件开发常见流程之移动端调试方法,利用Chrome(谷歌浏览器)的模拟手机调试,搭建本地Web服务器,手机和服务器在一个局域网,通过手机访问服务器,使用服务器,利用ip实现域名访问
软件开发常见流程之移动端调试方法,利用Chrome(谷歌浏览器)的模拟手机调试,搭建本地Web服务器,手机和服务器在一个局域网,通过手机访问服务器,使用服务器,利用ip实现域名访问
|
4月前
|
Web App开发 编解码
软件开发常见流程之兼容性和手机屏页面设计,PC端和移动端常见浏览器,国内的UC都是根据Webkit修改过来的内核,开发重点关注尺寸,常见移动端尺寸汇总,移动端,理想视口根据你设别的样式进行修改
软件开发常见流程之兼容性和手机屏页面设计,PC端和移动端常见浏览器,国内的UC都是根据Webkit修改过来的内核,开发重点关注尺寸,常见移动端尺寸汇总,移动端,理想视口根据你设别的样式进行修改
|
5月前
|
移动开发 前端开发 JavaScript
浏览器端图表渲染技术SVG, VML HTML Canvas
浏览器端图表渲染技术SVG, VML HTML Canvas
40 0