浏览器渲染——(一)渲染过程

当浏览器渲染一个html都发生了什么?

这个问题基本在面试的时候经常会问到吧。经常的回答是当html 被加载到浏览器中,解析html构建dom tree,通过link解析css,构建render tree。把这俩个组合在一起,渲染出看到的页面。(精简的回答。)对的,但不全面。本文进行深度剖析。

一,图解流程


1,解析代码。浏览器包含html解析器和css解析器。分别解析html和css代码。html解析器会解析出dom,css解析器会解析出cssDom。cssDom的样式映射都是全部计算过的,是个绝对值。我们在代码中写的往往不是最终结果(元素可能继承,默认,calc等其他影响,浏览器不理解相对概念只会以绝对值展示)。dom和cssDom都是树型结构。

2,合并树,从Dom根结点开始遍历每一个可见的节点,为其找到适配的cssDom规则并应用。将两个树合并成render tree 。a.某些节点不可见(如脚本标签<script>此类)b.某些节点被CSS隐藏了,类似display:none。注意,visibility:hidden此类属于可见节点,其仍然占据着布局空间。最终输出的RenderTree将同时包含屏幕上的所有可见内容及其样式信息。

3,layout,css提供了部分布局信息,但浏览器想要的是元素相对于设备视窗内的确切位置和大小。仅仅靠render tree是不足以描述我们的页面,我们缺乏节点之间确切的位置关系。浏览器默认通过文档流进行布局,并通过css盒模型来描述每一个元素。所以我们可以轻易的捕获元素在视窗内的确切尺寸和大小,所有的相对测量值都会转换成屏幕上的绝对像素。诸如float,flex之类的布局方式都需要重新计算。布局信息会被存储在一个与渲染树相关联的树结构里。layout阶段结束后会输出名为layoutTree的数据结构。

4,painting ,遍历渲染树,进行每个节点的绘制。

二,浏览器的进程

对于进程和线程的定义和理解请参考以下链接:

1,https://segmentfault.com/a/1190000012925872

2,http://imweb.io/topic/58e3bfa845e5c13468f567d5

以目前的Chrome为例,它采用的是多进程架构。不同的进程有不同的功能。比如browser process主要负责浏览器界面显示,与用户交互。包括地址栏,书签,后退和前进按钮等。页面的渲染主要是在renderer process中进行的。

1,Renderer process下的线程

a,主线程(main thread)

b,合成线程(COmpositor thread)

一般情况下,诸如计算HTML 元素的 CSS 样式,layout,paint和运行JavaScript都运行在主线程之中。我想你已经注意到了,js的运行也在主线程。这就是意味着,样式计算,layout,paint和js的执行是一种互斥关系。它们会互相阻塞。如果正在计算布局,那么js就无法及时的监听到事件。反过来,js执行占据了大量主线程时间,你的layout和paint都会受到影响。

概览

主线程:图层的诞生

原有的layoutTree可以反映在二维平面上节点的相互关系,但无法反映层次关系。


这是俯视角下的页面


浏览器引入图层概念来处理代码中复杂的层次关系。(z-index,fixed等,所以页面关系可能不止一层)



这是一个demo

GraphicsLayer结束后还会转换为cc layer。但是树的结构不会再有更改。可以理解GraphicsLayer就是我们最终需要生成的图层。


这是一个demo

chrome会将它认为是同一层坐标体系下的layoutObject归为一个Layer内。

每一个LayoutObject都直接的或间接的与一个PaintLayer有关联。那些共享同一坐标空间的LayoutObject往往处在同一PaintLayer中。如果没有触发上述条件,会和父元素共享一个坐标空间。

特殊的dom,canvas,video,根对象。特殊的css,css位置属性,transform,透明度,filter等。


chrome会将它认为是一层的paintLayer归为一个GraphicsLayer内。

事情并没有结束,chrome觉得目前的曾数量依然太多了。所以PaintLayer依然要继续变形,继续压缩层的数量。由paintLayer转化成graphicsLayer。那么什么是GraphicsLayer呢?这里抛出一个可能大家都早已听说过得概念:合成层。GraphicsLayer就是最终合成的候选人。

主线程:PAINT


到目前为止,我们仍然还在主线程中。我们刚刚这一系列layer的转换,都发生在layout和paint中间。当我们满心欢喜的拿到合成层时,是不是觉得快结束了,终于绘制了!很遗憾,这个Paint可能和你想象中的阶段不大一样。


笼统的将三个阶段解读为一个Painting阶段是不严谨的,实际上Paint仅仅是其中第一个阶段而已。传递给Paint的是CC Layer。所以每一层都拥有独立的Paint。每层都会拥有一个DisplayItem List来记录该层所有的绘制操作。注意,只是记录操作,没有任何绘制行为的发生。Displayitem list会与合成层绑定,然后合成层被当做主线程的最终输出交给合成线程

合成线程:Commit


commit阶段,主线程会提交一份cc layer的拷贝放入合成线程。随后主线程便会进入下一帧的渲染流程中。两个线程同步进行,互不影响。commit阶段虽然会短暂阻塞主线程,但是时间开销很小。

合成线程:Tiling(铺砖,盖瓦的意思)


一个页面的实际长度可能远远超过视窗大小。将整个页面每次都渲染出来是不明智的,因为用户未必真的会浏览到视窗外的部分,这样反而消耗了资源。除了纵横向滚动依次排列的磁贴,在存在zoom缩放操作时,也会根据每次缩放的情况来决定渲染哪些磁贴。所以在一些性能较差的手机上,对超长列表进行快速滚动,有时可以发现底部会有短暂白色的情况。这正是tiling阶段动态渲染的原因。

合成线程:Raster

主线程中paint阶段生成的命令会在该阶段执行,将图像压进位图之中。位图就是像素点阵图。光栅化就是将图像画进位图的过程。之前我们在paint存储的绘制指令现在会拿出来执行,以磁贴为单位。光栅化结束后这些位图会上传至GPU内存之中。


合成线程:Activation


合成线程内有两棵树。active树在执行完draw阶段提交gpu线程绘制后,下一帧的pendingTree便可以继续工作了,不必等待画面完全输出至页面上。一帧画面只有真正activation之后变成active Tree才算进入渲染流程。

合成线程:draw

draw阶段仍然是对指令的包装。每个tile都会被“绘制”成“绘图块(draw quads)”。每一个绘图块是一个在屏幕上指定位置绘制tile的指令。这个有点像我们在主线程Paint阶段做得事。每一个块都会包含对相应tile在gpu内存中的引用。而所有绘图块会被包装在一个CompositorFrame对象中。这个对象就是最终合成线程的终点,或者说,它就是整个renderer process的最终输出。这个对象会被提交给browser process。



合成线程:display

Browser process会整合各个process提交的compositorFrame,让gpu输出真正的最终画面。除了rederer process渲染的主页面。plugin process也会影响画面。那些我们常用的Chrome插件就是在这个阶段与我们的页面进行整合的。


以上就是渲染的全部过程。当然页面也会因其他因素而改变。

1,用户交互(包括滚动,缩放,点击等一系列操作)

2,js对dom的更新。

用户交互


js更新dom

JS对DOM的更新是需要谨慎的,它往往会触发从主线程到合成线程中的所有阶段!

虽然听起来很可怕,但是只要不是短期内反复更新,现在的机器性能都足以应对。但如果是一个无线循环动画之类的,就需要万分谨慎了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容