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