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(轮廓)