之前我有总结过一篇经典面试题:浏览器从输入URL到页面渲染过程 ,接下里我将对某些知识点进行更细致的解析。

浏览器从输入URL到页面渲染过程 系列文章:

(一):浏览器从输入URL到页面渲染过程 —— 浏览器的进程与线程

————————————————————————————————————————————————————

浏览器从输入URL到页面渲染过程 ——页面渲染流程

浏览器的渲染机制很复杂,从输入HTML到页面输出大致分为以下这些步骤:

构建DOM树 > 构建styleSheets树 > 布局 > 分层 > 绘制 >分块 > 光栅化 > 合成

构建DOM树

  • 为什么要构建 DOM 树?

    因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树。

    什么是树结构:节点与节点之间通过父子关系相连接。

    具体流程如下:

我们在chrome的控制台输入:document ,便能看到此DOM树结构:

虽然 DOM树 和 HTML 看起来并没有什么的区别,但是DOM树在内存中是以树状结构存储的,可以被JS代码所查询操作。例如:

document.getElementsByTagName("p")[0].innerText = "black"


样式计算(构建styleSheets)

  • 为什么要构建 styleSheets ?

    和 HTML 文件一样,浏览器也是无法直接理解这些纯文本的 CSS 样式,所以当渲染引擎接收到 CSS 文本时,会执行一个转换操作,将 CSS 文本转换为浏览器可以理解的结构——styleSheets。

  • 什么是浏览器可以理解的style?

    rem/em ————> px
    color: blue ————> rgb(0, 0, 255)
    font-weight: blod ————> 700

  • CSS来源有哪些呢?

    1、通过 link 引用的外部 CSS 文件
    2、< style >标记内的 CSS
    3、元素的 style 属性内嵌的 CSS


如果这三个地方都有对同一标签进行样式定义,或者该标签没有被定义样式,那它的最终样式会是什么样的呢?这时候,就需要进行样式计算了。

样式计算规则:继承规则层叠规则

继承规则:当前标签的样式继承了其所有父标签的样式。
层叠规则:多个样式同时作用于该标签时,进行样式层叠。

当然,我们在控制台输入 document.styleSheets 看到styleSheets结构:

布局(构建render树)

有了 DOM树 和 styleSheets树,接下来我们就可以将两棵树进行合并,生成render树。


在生成render树时,浏览器首先遍历 DOM 树中的所有可见节点,并把这些节点加到布局树中,而不可见的节点会被布局树忽略掉,如 head 标签下面的全部内容,再比如 body.div.span 这个元素,因为它的属性包含 dispaly:none,所以这个元素也没有被包进布局树。

当然,这只是第一步,光有这些标签和对应的样式是无法绘出页面图的,渲染进程还需要计算出每一个标签所对应在页面上的物理位置,再将其位置存储到render树中。

分层

虽然有了render树及对应的物理坐标,但浏览器也不能直接进行页面绘制,因为页面上还涉及许多复杂的样式:transform, animation 动画、scroll,z-indexing改变层级等等,浏览器则为这些特殊的节点建立一个对应图层,生成图层树(LayerTree),将这些图层合并在一起,就是一整个页面的样式(类似于 photoshop 的图层)。

那什么时候会被提升为一个专门的图层,哪些应该被包含在同一图层?

1、拥有层叠上下文属性的元素

什么是层叠上下文?其实就是我们熟悉使用的z-index,MDN上是这么定义的:

其中有一句话很重要:

 重要的是,其子级层叠上下文的 z-index 值只在父级中才有意义。

不知你在使用z-index时,有没有遇到这样一个情况:

有时,你想要某一个图片或者文字 置于 某一块 的上方,于是使用z-index进行层级提升,但是就算设置了z-index确没有起作用。

正式因为 子级层叠上下文的 z-index 值只在父级中才有意义 ,只有当 父级的 position 为 absolut 或者 relative 时才有效。

2、需要剪裁的地方也会被创建为图层。

当父容器的宽高不足以撑起子容器的宽高,出现滚动条 或者 设置 父容器 为overflow :hode 等等,子容器页面就会被裁剪,这时浏览器也会为其创建出单独的图层。

如何查看图层?

打开 chrome 控制台,选择 Layers, 点击旋转按钮,对图层进行拖拽到有一定的倾斜度时,便能很直观的看到页面的图层分布 :

绘制

创建完图层后,接下来就是对图层进行绘制绘制,简单的说就是将图层重叠在一起。

如果给我们一张图,我们会怎样进行绘制呢?

一般我们会对这张图进行拆分:

1、先画出最外层的红色框图
2、在画出中间层绿色框图
3、最后画出里面层黄色框图

浏览器也是如此,将这些图层拆分为一条条的指令,然后一条一条逐步执行,最后进行绘制:

分块

为什么需要分块? 再此之前我们需要了解一下什么是视口:我们在当前屏幕区域能看到的模块就叫视口。当页面内容很长时,页面就会出现滚动条,但是当前视口大小有限,我们只能看到一部分,所以在这种情况下,要绘制出所有图层内容的话,就会产生太大的开销,而且也没有必要。

这个时候渲染进程会再次将这些图层分成很多图块。

格珊化

什么是格珊化?

渲染进程将这些图层分成很多图块后,然后按照视口附近的图块来通过 栅格化 优先生成位图。所谓栅格化,是指将图块转换为位图。而图块是栅格化执行的最小单位。

最后,我们来看一张流程图:

之前的生成DOM树、styleSheets树、render 树、分层、绘制都是在渲染引起的主线程中运行的, 绘制列表记录好绘制顺序和绘制指令的列表后,将其提交给渲染引擎中的合成线程,渲染进程还维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的。通常,栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中。

合成与显示

一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。

至此,整个渲染流程就走完了,总结为以下8步:

1、渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。
2、渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets树,并计算好 DOM 节点的样式。
3、将DOM与styleSheets树进行合成,创建布局(render)树,并计算元素的布局信息。
4、对布局树进行分层,并生成分层树。为每个图层生成绘制列表,并将其提交到合成线程。
5、合成线程将图层分成图块。
6、在光栅化线程池中将图块转换成位图。
7、合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
8、浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。

最后抛出两个问题:

1、为什么在优化 Web 性能的方法中,减少重绘、重排是一种很好的优化方式?

结合上文我们了解到,在布局这一过程中,将DOM树与styleSheets 合成render树后,渲染进程还需要计算出每一个标签所对应在页面上的物理位置,再将其位置存储到render树中,在执行下一步。

如果我们对页面进行了重排(改变标签的宽高、显示隐藏等物理层面的几何属性),那么渲染引擎将会把这一整套渲染流程重新跑一遍,浪费时间和空间。

如果我们对页面进行了重绘(改变标签的颜色、类名等样式属性),那么渲染引擎会直接进入 绘制 阶段,相较与重排,也提升了不少性能。

如果我们的操作不涉及重排和重绘,那么渲染引擎会直接进入 合成 阶段,大大的提高了性能。

2、如果下载 CSS/JS 文件阻塞了,会阻塞 DOM 树的合成吗?会阻塞页面的显示吗?

答案是肯定的,不论CSS还是JS文件下载阻塞,都会阻塞后续的流程。当从服务器接收HTML页面的第一批数据时,DOM解析器就开始工作了。
第一种情况:在解析过程中,如果遇到了JS脚本,如下所示:

<html><body>哈哈哈<script>document.write("--限制性js脚本")</script></body>
</html>

那么DOM解析器会先执行JavaScript脚本,执行完成之后,再继续往下解析。

第二种情况:我们内联的脚本替换成js外部文件,如下所示:

<html><body>哈哈哈<script type="text/javascript" src="foo.js"></script></body>
</html>

这种情况下,当解析到JavaScript的时候,会先暂停DOM解析,并下载foo.js文件,下载完成之后执行该段JS文件,然后再继续往下解析DOM。这就是JavaScript文件为什么会阻塞DOM渲染。

第三种情况,还是看下面代码:

<html><head><style type="text/css" src = "theme.css" /></head><body><p>哈哈哈</p><script>let e = document.getElementsByTagName('p')[0]e.style.color = 'blue'</script></body>
</html>

当我在JavaScript中访问了某个元素的样式,那么这时候就需要等待这个样式被下载完成才能继续往下执行,所以在这种情况下,CSS也会阻塞DOM的解析。

浏览器从输入URL到页面渲染过程 ——页面渲染流程相关推荐

  1. 浏览器从输入URL到页面渲染过程 —— 浏览器的进程与线程

    之前我有总结过一篇经典面试题:浏览器从输入URL到页面渲染过程,接下里我将对某些知识点进行更细致的解析. 浏览器从输入URL到页面渲染过程 系列文章: (二):浏览器从输入URL到页面渲染过程 --页 ...

  2. 从在浏览器中输入URL到页面渲染出来的完整过程是怎样的?

    从宏观上看,主要包括以下几个步骤:域名解析.建立连接.发送请求.响应数据.关闭连接.下面以在Chrome浏览器中输入https://yq.aliyun.com/articles/580962为例,讨论 ...

  3. 浏览器从输入url到页面加载完成发生了什么

    最近看了一些前端面试方面的一些题目,看了网上许多相关的文章,发现有一个问题始终绕不开: 在浏览器中输入URL到整个页面显示在用户面前时这个过程中到底发生了什么.仔细思考这个问题,发现确实很深,这个过程 ...

  4. 深入浅出经典面试题:从浏览器中输入URL到页面加载发生了什么 - Part 3

    备注: 因为文章太长,所以将它分为三部分,本文是第三部分. 第一部分:深入浅出经典面试题:从浏览器中输入URL到页面加载发生了什么 - Part 1 第二部分:深入浅出经典面试题:从浏览器中输入URL ...

  5. 从浏览器地址栏输入url到显示页面的步骤

    从浏览器地址栏输入url到显示页面的步骤(以HTTP为例) - 在浏览器地址栏输入URL - 浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤     - 如果资源未缓存,发起新请求   ...

  6. java 重定向到某个页面并弹出消息_前端面试100问之浏览器从输入URL到页面展示发生了什么...

    点击蓝字,关注我们 『浏览器从输入URL到页面渲染发生了什么』作为一个经典题目,在前端面试中高频出现,很多大厂的面试都会从这个面试题出发,考察候选人对知识的掌握程度,这其中涉及到了网络.操作系统.We ...

  7. 前端学习之浏览器从输入URL到页面加载的全过程

    浏览器从输入URL到页面加载的全过程 从输入URL到页面加载的主干流程如下: 1.浏览器的地址栏输入URL并按下回车. 2.浏览器查找当前URL的DNS缓存记录. 3.DNS解析URL对应的IP. 4 ...

  8. 「高频面试题」浏览器从输入url到页面展示中间发生了什么

    作者:Hanpeng_Chen 公众号:前端极客技术 文章首发个人博客:「高频面试题」浏览器从输入url到页面展示中间发生了什么 | 代码视界 "在浏览器中,从输入URL到页面展示,中间发生 ...

  9. 【重难点】【计算机网络 01】OSI 七层模型和 TCP/IP 四层模型、IP 地址分为哪几类、ping 的原理、从浏览器地址栏输入 URL 到显示网页的过程、什么是 socket

    [重难点][计算机网络 01]OSI 七层模型和 TCP/IP 四层模型.IP 地址分为哪几类.ping 的原理.从浏览器地址栏输入 URL 到显示网页的过程.什么是 socket 文章目录 [重难点 ...

最新文章

  1. nethogs监控linux流量
  2. 阅读量PHP设计,zblogPHP如何修改文章阅读量
  3. (转) 各种好用的插件 Xcode
  4. jggrid标红列和动态标红行的几种方法
  5. Android starting 4---四大组件之一---Activity入门
  6. 机器学习笔记(一)——贝叶斯决策
  7. vs2015环境搭建与简单程序测试
  8. 快手作者视频如何批量下载
  9. RGB颜色 取色器/拾色器 颜色混搭
  10. 怎么修改chrome浏览器的字体
  11. 雨林木风四大绝笔系统下载
  12. android fps测试 apk,性能测试 查看Android APP 帧数FPS的方法
  13. Python-Selenium自动化登陆QQ空间
  14. Redis可视化工具
  15. web技术基础---网站设计说明书
  16. CSS 固定定位 position fixed
  17. 浏览器被hao360劫持解决办法
  18. 大数据可视化设计师丹尼斯_自助数据可视化设计师如何谋生
  19. java读者信息管理课程设计_Java课程设计—学生成绩管理系统(201521123002 林楚虹)...
  20. AI的下一个战场:认知智能的突围

热门文章

  1. 2020-08-20
  2. hive的一些常见内置函数
  3. java多线程笔记补充之 线程控制操作
  4. inline函数和一般的函数有什么不同
  5. 关于python 和C++使用cv画矩形并填充颜色同时填充文字
  6. 足不出户,确保交付——独家交付秘籍(第二回)
  7. iLogtail使用入门-iLogtail本地配置模式部署(For Kafka Flusher)
  8. 一图看懂云栖大会「云原生」发布
  9. 拥抱创新,持续探索——对话阿里云MVP胡逢法
  10. 图(关系网络)数据分析及阿里应用