乐趣区

关于前端:浏览器原理编译流程初探

Browser Introduction

浏览器基础架构

浏览器次要组成部分

渲染引擎的根本工作流

Parsing & DOM tree construction

解析流程

编译流程

DEMO

2 + 3 – 1


词法剖析:
这个语言能够蕴含整数、加号和减号。


语法分析:
语法构建块是表达式、术语、操作。
这个语言可蕴含任何数量的表达式。
一个表达式被定义为:一个术语前面跟着一个操作,操作前面跟着另一个术语。
一个操作就是一个加号或一个减号
一个术语是一个整数或一个表达式。

HTML 解析遵循的准则:

W3C: HTML 的词汇和语法规定
DTD: Document Type Definition 文档类型申明
软语法!== XML XHTML

DOM Document Object Model
咱们看一个例子

被解析为

解析算法流

语言的宽容个性:浏览器容错,以反对家喻户晓的有效 HTML 案例。解析过程是可重入的(reentrant)。document.write

标记算法

DOM 树结构算法


当解析器创立好时,Document 对象也创立好了

在树的构建阶段,会扭转蕴含 Document 根节点的 DOM 树,还会增加元素到 DOM 树。每个被分词器开释的节点都将被树构建器加工

对于每个标记,标准会定义与它绝对应的 DOM 元素,并且为该元素创立这个 DOM 元素

除了将元素增加到 DOM 树中外,还会将元素增加到一个凋谢元素的堆中。这个堆用于修改嵌套谬误和未敞开的元素。

构建算法是通过状态机的模式示意的。这些状态叫作 ” 嵌入模式 ”。

解析完结的操作

浏览器会标记文档是可交互的,而后开始解析 ” 提早 ” 模式(deferred mode)下的脚本——在文档解析实现后执行。此时,文档状态变成 “ 实现 ”,抛出一个 “load” 事件。

浏览器容错

在 HTML 页面上,永远不会呈现 “ 有效语法 ”(Invalid Syntax)的谬误。浏览器会修改它,而后持续运行。

浏览器容错机制







CSS 解析器

解析 JS

网络模型是同步的【同步 async defer】
预解析

当有款式在加载和解析时,Firefox 会阻塞所有的脚本。
Webkit 仅会阻塞这些试图获取特定的款式属性,这些属性可能会受未加载的款式影响,的脚本。

Render tree construction

渲染引擎的根本工作流

webkit 主流程

Gecko 主流程

渲染树 由可视元素组成,

        这些元素按将要展现的顺序排列。它是文档的视觉出现。渲染树的目标是保障内容有序绘制。

一个渲染器晓得如何布局和绘制本身及其子类。

Firefox 把渲染树中的元素叫作 “ 帧 ”(frames)。

Webkit 把这些元素叫作 “ 渲染器 ”(renderer)或 “ 渲染对象 ”(render object)。

webkit 盒模型

Render 树的构建

1 渲染器与 DOM 元素绝对应,但并不是一对一的关系。非可视元素不会被插入到渲染树,比方 head 元素。display !== visibility
2 有些 DOM 元素会对应多个可视对象。有些元素构造比较复杂,所以不能用单个矩形来示意。比方,select 元素有 3 个渲染器
3 当文本在一行内显示不下,被拆分成多行时,新行中的文本会被增加到新的渲染器中。
4 如果行内元素既蕴含了行内元素又蕴含了块级元素,会创立一个匿名块级渲染器包裹这些行内元素。
5 有些渲染对象与 DOM 节点一对一对应,然而在树中的地位却不同。浮动和相对定位的元素脱离了流,搁置在树的不同地位,而后映射到理论的帧。它们存在于占位符帧中。

渲染树和与之对应的 DOM 树,Viewport 是初始的蕴含块。
在 Webkit 中,Viewport 是 RenderView 对象。

Webkit 中,合成款式和创立渲染器的过程叫作 “ 附着 ”(attachment)。每个 DOM 节点都有一个 attach 办法。” 附着 ” 是同步的,节点插入到 DOM 树中会调用新节点的 attach 办法。
Firefox 中,构建过程体现为为 DOM 的更新注册一个监听器(listener),而后将帧的创立委派给“帧构建器”,构建器会合成款式,创立帧。

款式计算

构建渲染树须要计算每个渲染对象的可视属性。通过计算每个元素的款式属性来实现

款式计算带来了一些难题

1、款式数据的构造宏大,蕴含了许多的款式属性,可能会引起内存问题。
2、如果没有优化,那么为每个元素查找匹配规定会导致性能问题。为每个元素查找匹配遍历整个规定表是一项沉重的工作。

  选择器能够有简单的构造,这会导致匹配过程会从看上去有心愿的门路开始匹配,而实际上却是有效的,而后再去尝试新的匹配门路。

3、利用规定波及非常复杂的级联规定,这些规定定义了规定的层次结构。

共享款式数据(Sharing style data)

Webkit 节点援用款式对象(渲染款式 RenderStyle)。这些对象在某些状况下,能够被节点共享。这些节点是兄弟节点以及:

1、这些元素必须在雷同的鼠标状态下(比方,不能一个是 :hover 状态,其余的不是)
2、元素不应该有 ID
3、标签名称应该能匹配
4、class 属性应该能匹配
5、映射属性集必须完全相同
6、link 状态必须匹配
7、focus 状态必须匹配
8、元素不能受到属性选择器的影响,影响被定义为可匹配到应用了元素中的任何属性的属性选择器。
9、元素不能存在行内款式属性
10、不能应用兄弟选择器。WebCore 遇到兄弟选择器时会抛出一个全局开关,为整个文档敞开款式共享。这些选择器包含:+ 选择器,:first-child 和 :last-child 等。

Firefox 规定树(Firefox rule tree)
为了更简略的款式计算,Firefox 提供了两种树

规定树和款式上下文树。

Webkit 也有款式对象,然而他们不是贮存在相似于款式上下文树的树中,它只有 DOM 节点指向相应的款式。
渐进的过程:
Webkit 应用一个标记来标记顶层样式表是否加载实现(包含 @imports)。
当应用款式时,发现款式没有齐全加载实现,将会应用占位符,并且在文档中进行标记,当款式加载实现时,会从新进行计算。

Layout & Painting

Layout

渲染器创立实现并被增加到渲染树时,它没有地位(position)和 大小(size)。

计算这些值的过程叫作 布局(layout)和 回流(reflow)

HTML 应用基于流的布局模型,从左到右、从上到下。
但也有例外——比方 tables,就须要屡次计算(3.5)

坐标零碎和根框架相干,应用上侧和左侧坐标。

布局是一个递归的过程。从根渲染器开始,与 HTML 文档的元素绝对应。布局会在其中一些或所有框架层级中继续递归,为每个渲染器计算几何信息。

根渲染器的地位是 0,0,它的大小是视口大小——浏览器窗口的可视局部。

所有的渲染器都有一个 layout(布局)和 reflow(回流)办法,每个渲染器都会调用那些须要布局的子渲染器的 layout 办法。

脏值零碎

为了防止为每个小的变动都进行一次残缺的布局,浏览器应用了脏值零碎。

一个渲染器扭转或增加了之后会标记本人及其子代为“dirty”——须要布局。

有两种标记——“dirty”和“children are dirty”。后者意味着尽管渲染器自身没问题,然而它至多有一个须要布局的子代。

布局过程

布局通常有上面几种模式:

父渲染器决定本人的宽度
父渲染器遍历子渲染器,而后
搁置子渲染器(设置它的 x 和 y)
如有须要,调用子渲染器的 layout(布局)办法——它们是脏的或者咱们在全局布局中,或者其余某些起因——这会计算子渲染器的高度。
父渲染器应用子渲染器的高度、外边距、内边距的累加高度来设置本人的高度——父渲染器的父渲染器也会应用这个高度。
设置脏值为 false。

在一个渲染器在布局过程中发现须要折行,它会停下来,告诉父渲染器它须要折行。父渲染器就会创立额定的渲染器,而后调用这些渲染器的 layout 办法。

Painting

在绘制阶段,会遍历渲染器树,调用渲染器的 paint 办法,在屏幕上排列内容。绘制应用 UI 根底组件
CSS2 规定了绘制程序的程序。这实际上就是元素在层叠上下文(stacking context)中如何层叠的程序。

一个块级渲染器的层叠程序如下:

background color(背景色彩)
background image(背景图片)
border(边)
children(子级)
outline(轮廓)

退出移动版