前言

对于HTML,css和JavaScript是如何变成页面的,这个问题你了解过吗?浏览器究竟在背后都做了些什么事情呢?让我们去了解浏览器的渲染原理,是通往更深层次的开发必不可少的事情,能让我们更深层次,多角度的去考虑性能优化等问题。

HTML,css,JavaScript数据经过中间渲染模块的处理,最终显示在页面上(其中HTML超文本标记语言,CSS层叠样式表,JS为JavaScript,大家一般都知道是什么,写过网页的朋友,学习者大都知道的)。

  • HTML的内容是由标记和文本组成
  • CSS称为层叠样式表,是由选择器和属性组成
  • JS是可以使网页的内容“动”起来

有人说渲染流程可以分为:构建DOM树,样式计算,布局阶段,分层,绘制,分块,光栅化和合成等。其中浏览器复习一下,它是多线程的的,js是单线程的,JS在浏览器中,它可以是多线程的。

下面围绕浏览器渲染原理话题开始描述,为什么要了解浏览器渲染页面机制呢?。

浏览器渲染原理

首先,JavaScript引擎是基于事件驱动单线程执行的,渲染线程负责渲染浏览器界面,但是GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI的更新也会被保存在一个队列中,等到JS引擎空闲时才有机会被执行。
面试官问我Chrome浏览器的渲染原理(6000字长文)_html

那么什么是DOCTYPE以及作用呢

DTD,document type definition, 文档类型定义,是一系列的语法规则,用来定义XML或(x)HTML的文件类型。浏览器会使用它来判断文档类型,决定使用何种协议来解析,以及切换浏览器模式。

DOCTYPE是用来声明文档类型和DTD规范的,一个主要的用途便是文件的合法性验证。如果文件代码不合法,那么浏览器解析时便会出一些差错。

下图为浏览器的渲染过程图:
面试官问我Chrome浏览器的渲染原理(6000字长文)_html_02

重排Reflow

重排的定义:DOM结构中的各个元素都有自己的盒子模型,这些都需要浏览器根据各种样式来计算并根据计算结果将元素放到它该出现的位置,这个过程称之为reflow.

触发Reflow情况

  • 当你增加,删除,修改Dom节点时会导致Reflow或Repaint
  • 当你移动DOM的位置,或是搞个动画的时候
  • 当你修改CSS样式的时候
  • 当你Resize窗口的时候,或是滚动的时候
  • 当你修改网页的默认字体时

重绘Repaint

重绘的定义,当各种盒子的位置,大小以及其他属性,例如颜色,字体大小等都确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是页面的内容出现了,这个过程称为repaint。

触发Repaint情况

  • DOM改动
  • CSS改动

讲到这里,下面来细分说一下吧!

简单介绍一下浏览器的工作原理
面试官问我Chrome浏览器的渲染原理(6000字长文)_html_03

  1. 了解浏览器

目前使用的主流的浏览器:Internet Explorer,Firefox,Safari,Chrome浏览器,Opera。让我们看看浏览器统计数据的占比:

面试官问我Chrome浏览器的渲染原理(6000字长文)_html_04

让你说说浏览器的主要功能:

就是向服务器发出请求,在浏览器窗口中展示您选择的网络资源,资源一般指HTML文档,可以是PDF,图片或其他的类型。资源的位置由用户使用URI(在电脑术语中,统一资源标识符(Uniform Resource Identifier,URI)是一个用于标识某一互联网资源名称的字符串)

  1. 浏览器的结构
  • 用户界面:包括地址栏,前进、后退按钮,书签菜单等。
  • 浏览器引擎:在用户界面和呈现引擎之间传送指令。
  • 呈现引擎:负责显示请求的内容。
  • 网络:用于网络调用,比如HTTP请求;其接口与平台无关,并为所有平台提供底层实现。
  • 用户界面后端:用于绘制基本的窗口小部件,比如组合框和窗口。其公开了与平台无关的通用接口,而在底层使用操作系统的用户界面方法。
  • JavaScript解释器:用于解析和执行JavaScript代码。
  • 数据存储:这是持久层。浏览器需要在硬盘上保存各种数据,例如Cookie。新的HTML规范定义了“网络数据库”,这是一个完整的浏览器内数据库。

注意:Chrome浏览器的每个标签页都分别对应一个呈现引擎实例,每个标签页都是一个独立的进程。

  1. 呈现引擎

呈现引擎的作用是“呈现”,用于在浏览器的屏幕上显示请求的内容。

一般情况下,呈现引擎可显示HTML和xml文档与图片,通过插件或浏览器扩展程序,可以显示其他类型的内容。浏览器(Firefox,Chrome浏览器和Safari)是基于两种呈现引擎构建的。

Firefox使用的是Gecko,而Safari和Chrome浏览器使用的是WebKit(WebKit 是一种开放源代码呈现引擎)。

  1. 主流程

呈现引擎一开始会从网络层获取请求文档的内容,其大小一般限制在8000个块以内。

呈现引擎将开始解析HTML文档,并将各标记逐个转化成“内容树”上的DOM节点。同时也会解析外部CSS文件以及样式元素中的样式数据。呈现树构建完后,会进入“布局”处理阶段,也就是为每个节点分配一个应出现在屏幕上的确切坐标。

  1. 解析

解析是呈现引擎中重要的环境,什么是解析呢?

解析文档是指将文档转化成为有意义的结构,可以让代码理解和使用的结构。解析得到的结构通常是代表了文档结构的节点树,它称为解析树或者语法树。

  1. 语法

解析是以文档所遵循的语法规则为基础的。解析的过程分为两个子过程:词法分析和语法分析。

什么是词法分析呢?

词法分析是将输入内容分割成大量标记的过程,标记(语言中的词汇),构成内容的单位。相等于语言中的单词。

什么是语法分析呢?

语法分析是应用语言的语法规则的过程。

so,解析器一般解析工作分两个组件处理,为词法分析器(负责将输入内容分解成一个个有效标记),解析器负责根据语言的语法规则来分析文档的结构,来构建解析树。

从源文档到解析树:Document->Lexical Analysis->Syntax Analysis->Parse Tree

解析是一个迭代的过程。

是这样的,解析器会向词法分析器请求一个新标记,并尝试将其与某条语法规则进行匹配。如果匹配规则,解析器就会将对应与该标记的节点添加到解析树中,然后继续下一个。

但是如果没有匹配的规则,解析器会将标记存储到内部,继续请求标记,直到可与之匹配的规则,但是如果没有直到的话,就会引发异常(文档无效,包含语法错误等)。

  1. 翻译

解析通常是在翻译的过程中,而翻译是将输入的文档转换为另一种形式,如编译器将源代码编译成机器代码,流程是将源代码解析成解析树,将解析树翻译成机器代码文档。

编译流程:Source Code -> Parsing->Parse Tree -> Translation -> Machine Code

  1. 解析器类型

两种基本的解析器类型:自上而下解析器,自下而上解析器

自上而下就是: 解析器从语法的高层结构出发,尝试从中找到匹配的结构。

自下而上就是: 解析器从低层规则出发,将输入内容逐步转化为语法规则,直至满足高层规则。

你知道一种工具叫解析器生成器吗,它能够帮助你生成解析器,你只要向它提供你所使用的语言的语法,即词汇和语法规则,然后就会生成相应的解析器。

你晕了吗?可以点击这里查看:浏览器的工作原理:新式网络浏览器幕后揭秘

https://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/

渲染机制

浏览器从接收到页面开始到页面显示,这整个过程中的所有步骤,称 关键渲染路径 ,一般分为两步:页面内容加载完成和页面资源完成,分别对应于DOMContentLoaded和Load

关键:网页的渲染过程如下,包含页面加载和页面渲染两个过程。

页面加载过程是,从服务器请求资源并构建DOM树的过程,网页渲染过程指的是通过DOM树渲染出视图内容。

首先 浏览器加载网页内容,使用HTML解释器 将网页 转变 为一系列的 token,再根据token 构建 dom 树, 当一个可见的 dom 节点 插入到dom 树时,浏览器会构建一个renderObject 节点并将其插入到 render 树中。

Render 树包含节点的样式信息,可以简单理解为 dom + css构成。Render树将交由排版引擎处理,计算出每一个RenderObject 节点的大小和位置等信息,然后再交给由渲染引擎完成页面的内容绘制。

DOM + CSS -> Render Tree

复习一下整个关键渲染包括:

  • 解析HTML,生成DOM树(DOM)
  • 解析CSS,生成CSSOM树
  • 将DOM和CSSOM合并,生成渲染树(Rendere-Tree)
  • 计算渲染树的布局Layout
  • 将布局渲染到屏幕上Paint

面试官问我Chrome浏览器的渲染原理(6000字长文)_javascript_05

那么要问了,为什么要了解浏览器渲染页面机制呢?

了解渲染机制,主要还是为了性能的优化:

了解浏览器如何进行加载,引用外部样式文件,JS文件时,将它们放到合适的位置,是浏览器最快的速度让文件加载完毕;了解浏览器如何进行解析,选择最优的写法,构建DOM结构,组织CSS选择器的时候,是为了提高浏览器的解析速率;了解浏览器如何进行渲染,是可以减少“重绘”,“重新布局”的消耗。

那么上面一直说了解渲染机制,出现的几个基本概念,这里先弄明白:

  • DOM: Document Object Model,浏览器将HTML解析成树形的数据结构
  • CSSOM: CSS Object Model,浏览器将CSS解析成树形的数据结构
  • Render Tree: DOM和CSSOM合并生成Render Tree
  • Layout: 计算出Render Tree每个节点的具体位置
  • Painting: 通过显卡,将Layout后的节点内容分别呈现到屏幕上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Flt2ugQ0-1607909615056)(https://ask.qcloudimg.com/http-save/1435798/xant5t3qzl.png)]

当浏览器获取HTML文件后,会自上而下加载并在加载过程中进行解析和渲染;加载就是获取资源的过程;**如果在加载过程中遇到外部的css文件和图片,浏览器会另外发送一个请求,去获取css文件和图片,这个请求是异步的,并不会影响HTML文件的加载;但如果遇到JavaScript文件,**HTML文件会挂起渲染的进程,等待JavaScript文件加载完毕后,再继续进行渲染。

为什么需要等待JavaScript呢?

因为JavaScript可能会修改dom,导致后面的HTML资源白白加载,需要等待JavaScript文件加载完成后,再继续渲染,so,JavaScript文件一般写在底部body标签前的原因。

说说浏览器页面渲染:

  • 第一步:在CSS资源还没有请求回来之前,先生成DOM树;
  • 第二步:当所有的CSS请求回来之后,浏览器按照CSS的导入顺序,依次进行渲染,最后生成CSSOM树;
  • 第三步:把DOM树和CSSOM树结合在一起,生成有样式,有结构的RENDER TREE渲染树;
  • 最后一步:浏览器按照渲染树,在页面中进行渲染和解析

面试官问我Chrome浏览器的渲染原理(6000字长文)_html5_06

由于渲染机制过于复杂,渲染模块在在执行过程中划分了很多阶段,通过《浏览器工作原理与实践》-渲染流程上分:构建DOM树,样式计算,布局阶段;渲染流程下分:分层,图层绘制,栅格化(raster)操作,合成和显示。

整个渲染流程,从HTML到DOM、样式计算、布局、图层、绘制、光栅化、合成和显示。

面试一问:为什么要构建DOM树?

答:因为浏览器不能直接理解和使用HTML,so,需要将HTML转换为浏览器能够理解的结构,即是DOM树(树结构一般都了解了的)。

为了了解完整的DOM树结构,可以打开Chrome的“开发者工具”,或按F12,如图下:

面试官问我Chrome浏览器的渲染原理(6000字长文)_html5_07

接下来要让DOM节点拥有正确的样式,这就需要样式计算了。

样式计算的目的是为了计算出DOM节点中每个元素的具体样式:三步走

  • 把CSS转换为浏览器能够理解的结构
  • 转换样式表中的属性值,使其标准化
  • 计算出DOM树中每个节点的具体样式(涉及到CSS的继承规则和层叠规则)

当渲染引擎接收到CSS文本时,会执行一个转换操作,将CSS文本转换为浏览器可以理解的结构——styleSheets。属性值标准化的过程:将所有值转换为渲染引擎容易理解的、标准化的计算值。

DOM元素最终计算的样式如图:

面试官问我Chrome浏览器的渲染原理(6000字长文)_html5_08

布局阶段

布局:计算出DOM树中可见元素的几何位置,第一创建布局树(构建一棵只包含可见元素布局树),第二布局计算。

面试问题:CSS加载会阻塞页面显示吗?

  • css加载不会阻塞DOM树的解析
  • css加载会阻塞DOM树的渲染
  • css加载会阻塞后面js语句的执行

so,为了避免让用户看到长时间的白屏时间,应该提高css的加载速度。

为了防止css阻塞,引起页面白屏,可以提高页面加载速度

  • 使用cdn
  • 对css进行压缩
  • 合理利用缓存
  • 减少http请求,将多个css文件合并

面试问题:下载CSS文件阻塞了,会阻塞DOM树的合成吗?会阻塞页面的显示吗?

答:不会阻塞dom树构建的,因为HTML转化为dom树的过程,发现文件请求会交给网络进程去请求对应文件,渲染进程继续解析HTML。

会阻塞页面的显示,当计算样式的时候需要等待css文件的资源进行层叠样式,资源阻塞了,会进行等待,直到网络超时,network报出错误,渲染进程继续层叠样式计算。

说了DOM生成、样式计算和布局三个阶段,接下来说说后面的阶段。

说说分层:渲染引擎给页面分了很多图层,这些图层按照一定顺序叠加在一起,就形成了最终的页面。完成图层树的构建后,渲染引擎会对图层树中的每个图层进行绘制,为图层绘制。然后进行栅格化(raster)操作(绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的),最后合成与显示。

页面渲染机制图如下:

面试官问我Chrome浏览器的渲染原理(6000字长文)_达达前端指路_09

渲染过程图如下:

面试官问我Chrome浏览器的渲染原理(6000字长文)_html_10

浏览器渲染过程如下:

面试官问我Chrome浏览器的渲染原理(6000字长文)_vue.js_11

这里重点要说(重新说一下)两个概念回流和重绘

当render tree中的一部分因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。

每个页面至少需要一次回流,就是在页面第一次加载的时候。

在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。

当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。就叫称为重绘。

本篇文章的最后,留下一道思考题:减少重绘/重排能优化Web性能吗?如何能减少重绘/重排?

阅读资料

  • https://zhuanlan.zhihu.com/p/26105913
  • 浏览器工作原理与实践

总结

以上就是今天要讲的内容,本文仅仅简单介绍了Chrome浏览器的渲染原理流程,