浏览器工作原理及内核详解

浏览器主要功能

浏览器第一个主要功能就是从服务器下载Web资源并在浏览器窗口中将它呈现。这些资源可以是 HTML 文档,也可以是 PDF,图像等。而浏览器解析并显示 HTML 文档与如何处理 CSS 由 W3C组织 规范制定。以下是浏览器的组成要件:

  1. UI(用户界面):除了网页内容窗体以外的区域,包括地址栏、状态栏、工具栏、后退/前进按钮。

2.浏览器引擎:用户界面和呈现引擎之间传递指令。

  1. 呈现(渲染)引擎:负责解析并显示请求内容。

  2. 网络组件:负责网络请求,如 HTTP 请求。

  3. UI 后端:负责绘制基本的小部件,如系统模态弹窗。

  4. JavaScript 解析器:负责解析和执行 JavaScript 代码。

  5. 数据存储:浏览器需要保存在硬盘上的各种数据,如 Cookie、IndexedDB。

渲染引擎的基本流程

  1. 解析 HTML 文档构造 DOM 树。
  2. “渲染”过程将解析外部 CSS 文件和元素的样式属性,渲染树包含多个视觉效果并以正确的显示顺序的矩形。
  3. “布局”过程将每个节点定位在屏幕的确切坐标上。
  4. “绘画”过程遍历每个节点使用 UI后端涂漆(绘制)。

这是一个渐进的过程,为了更好的用户体验,渲染引擎会一边解析 HTML 一边开始构建和布局渲染,这个阶段一直保持与服务器通讯。

解析和 DOM 树构建

能把文档转换为有意义的结构并让计算机能够理解及使用,我们称之为解析,它必须遵循特定的语法规则并与上下文无关,解析的结果是具有文档结构的节点树,也叫作解析树或语法树。

解析器

解析可以分为两个子过程:词法分析语法分析

  • 词法分析:
    将输入分解成标记的过程,标记就是语言词汇(有效构建块的集合)。在人类语言中,相当于字典中的单词。

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

解析器就是负责将输入转换为有效标记,并根据语言的语法规则分析该文件结构并构造出解析树,词法分析会知道如何去除不相关的字符,比如空格和换行符。

有时候解析树并不是最终产品,通常还可以用于翻译,将输入文档转换为另一种格式。编译器会首先将源代码解析成解析树,然后将该树翻译成机器代码。

HTML 解析器

HTML 解析器的工作就是将 HTML 标记解析为解析树,HTML 的词汇及语法由 W3C组织 规范制定。HTML 是具有与上下文相关的语法组成,常规解析器无法解析 HTML文档。在与 XML 相比,两者也存在一些差异,HTML 语法“随意”、“松散”,XML 则“严谨”、“苛刻”,所以, XML 解析器无法解析 HTML

HTML DTD

DTD 文档类型定义用来定义 SGML 家族的语法,而 HTML 是基于 SGML 的。DTD 中包含允许出现的元素、属性和层次结构的定义,这也说明了 HTML 是与上下文有关的语言标记

DOM

DOM 文档对象模型提供了一套 HTML 文档元素与外部世界连接的标准接口,这些规范也由 W3C组织 制定,树的根节点就是“文档”对象。

HTML 解析算法

HTML 解析算法分为两个阶段:标记化和树构建。

标记化算法

标记化就是词法分析。该算法状态机来表示,每个状态接收输入流的一个或多个字符,并根据当前字符更新下一个状态。接收相同字符,对于正确的下一状态可能产生不同的结果。我们来看一个简单的例子:


  
    Hello world!
  

初始状态是“数据状态”。当遇到“<”字符时,状态更改为“标记打开状态”。接收“h”字符会创建一个“起始标记”,状态更改为“标记名称状态”,每消费一个字符都会附加在这个令牌名称上,保持这个状态直到遇见“>”字符,创建了一个“html”标记并发送。

接着状态回到“数据状态”,“”标记将按相同的步骤处理。到目前为止,一共有两个标记被发送。

继续回到“数据状态”,接收“Hello world”的“H”字符会创建一个“字符标记”,一共有11个“字符标记”被发送。

接收“”的“<”字符,状态再次回到“标记打开状态”,当接收下一个输入“/”会创建“结束标记”,状态更改为“标记名称状态”,继续接收“body”中的每个字符,直到遇见“>”,然后将新的标记被发送,状态回到“数据状态”,“”输入执行相同处理。

树构建算法

在这个阶段,对于每个标记与规范中定义的 DOM 元素相关,则将该标记追加到根节点为 Document 对象的 DOM 树上。该算法以状态机来表示。


  
    Hello world!
  

对应标记化阶段的第一模式是“初始模式”,接收发送过来的 html 起始标记,状态更改为“** Html 之前**”模式,将创建一个 HTMLHtmlElement 元素,并追加到 Document 对象上。

状态更改为“** Head 之前**”,显然没有收到 head 起始标记而是 body 起始标记,将隐式创建一个 HTMLHeadElement元素,并追加到 Document 对象上。

body 起始标记被重新处理,状态从为“** Head 之后”更改为“ Body 之前”模式,创建一个 HTMLBodyElement元素,并追加到 Document 对象上,同时状态更改为“在 Body 里**”。

现在接收到“Hello world”一系列字符标记,第一个“H”将创建和插入到“文本”节点,其它字符将附加到该节点上。

body 结束标记接收到后,状态更改为“** Body 之后”模式,接着又将接收到 html 结束标记,促使状态更改为“ Html 之后**”模式。接收文件的结束标记后将结束解析。

浏览器此时会将文档状态标记为“交互式”,并开始解析处于“延迟”模式的脚本程序,这些脚本将在解析文档后被执行,然后文档状态设置为“完成”,并触发“加载”事件。

浏览器容错

你将不会在 HTML 页面上看到“语法无效”的错误,浏览器会自动修复无效内容并继续,这种错误处理机制在其它浏览器中的做法是非常一致的,它不属于标准的一部分,就像书签和后退/前进按钮,都是浏览器多年来总结的经验。

CSS解析器

与 HTML 不同,CSS 是一个上下文无关的语法。语法在 BNF 中描述如下:

规则集
  : selector [ ',' S* selector ]*
    '{' S* declaration [ ';' S* declaration ]* '}' S*
  ;
选择器
  : simple_selector [ combinator selector | S+ [ combinator selector ] ]
  ;
简单选择器
  : element_name [ HASH | class | attrib | pseudo ]*
  | [ HASH | class | attrib | pseudo ]+
  ;
类
  : '.' IDENT
  ;
元素名
  : IDENT | '*'
  ;
属性
  : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
    [ IDENT | STRING ] S* ] ']'
  ;
伪
  : ':' [ IDENT | FUNCTION S* [IDENT S*] ')' ]
  ;

每个 CSS 样式表会被解析为一个 StyleSheet 对象,每个对象里包含 CSS 规则。CSS 规则对象包含选择器和声明对象以及 CSS 语法相对应的其它对象。

解析脚本和样式表的顺序

脚本

网络的模型是同步的,当解析器执行

你可能感兴趣的:(浏览器工作原理及内核详解)