一探浏览器幕后的《三俩事》上一篇的介绍让你们对浏览器的组成有了个模糊的认识:css
今天呢作渲染模块(WebKit)展开学习讨论。html
首先做为顺序介绍来讲。我应该具体介绍实现一个浏览器应该包含哪些内容(介绍一下chromium
实现包含了哪些内容)。可是考虑在前端
话题的介绍。只作简单的列举不作具体展开讨论;有兴趣能够自行下去学习。前端
其次按你们耳熟能详的程度来讲的话我应该着重讨论一下JS引擎(V8 event-loop相关)
;可是本节内容仍是想先介绍讨论一下渲染引擎(WebKit)
。不为别的我就是喜欢玩~ 由于我写这个系列的受众仍是偏向前端,因此涉及到须要代码介入讲解的部分这边采起JavaScript
来实现。node
画架构图画习惯了,不要在乎丑陋的细节 - -.
由上图能够获得渲染引擎内部解析执行大概过程的信息:
下面对于上文所提部分进行展开讨论一下 flow me~ gogogo!web
上面Parser的字眼是否是太多了。咱们获得一个信息解析是渲染引擎中很是重要的一个环节,因此首先须要介绍一下解析.正则表达式
解析文档是指将文档转化成为有意义的结构,也就是可以让代码理解和使用的结构。解析获得的结果一般是表明了文档结构的节点树,它称做解析树或者语法树。编程
解析是以文档所遵循的语法规则(编写文档所用的语言或格式)为基础的。比方说HTML解析那么是在HTML4/5的规范上进行的。全部能够解析的格式都必须对应肯定的语法(由词汇和语法规则构成)。canvas
解析过程一般是分红两个子过程:词法分析和语法分析。
词法分析是将输入内容分割成大量标记的过程。(进行切分可识别大量标记的词段)语法分析是应用语言的语法规则的过程(到底这段语言是要作什么工做)。segmentfault
HTML 解析器的任务是将 HTML 标记解析成解析树。浏览器
HTML 语法定义:
HTML 的词汇和语法在 W3C 组织建立的规范中进行了定义。
DOM
解析器的输出“解析树”是由 DOM 元素和属性节点构成的树结构。DOM 是文档对象模型 (Document Object Model) 的缩写。它是 HTML
文档的对象表示,同时也是外部内容(例如 JavaScript)与 HTML 元素之间的接口。
解析树的根节点是Document
对象。
DOM解析code示意(不能运行的) 首先要了解解析过程必定是迭代过程:
// 分析标记<>和属性的正则表达式 var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[\w-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/, endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/, attr = /([-A-Za-z0-9_]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; function ParserHTML(html){ // 接收参数html while(html){ // 匹配注释内容 if(html.indexOf("<!--") == 0){ // } // 匹配开始标签 if (html.indexOf("<") == 0) { match = html.match(startTag); if (match) { html = html.substring(match[0].length); //匹配截取 //继续迭代 } } if(html.indexOf("</") == 0){ //匹配结束标签操做 } } } // 输出示意结构 { element:"", parentNode:{}, childrenNode:{}, content:"", .... } // 我以前写的找不到了--, 你们能够试着去实现一下。有问题随时沟通 本示例正则可用。
CSS解析同HTML不一样地方是上下文无关的语法;可经过不少解析器作解析。
词法语法(词汇)是针对各个标记用正则表达式定义的:
comment \/\*[^*]*\*+([^/*][^*]*\*+)*\/
num [0-9]+|[0-9]*"."[0-9]+
nonascii [\200-\377]
nmstart [_a-z]|{nonascii}|{escape}
nmchar [_a-z0-9-]|{nonascii}|{escape}
name {nmchar}+
ident {nmstart}{nmchar}*
在 DOM 树构建的同时,浏览器还会构建另外一个树结构:渲染树。这是由可视化元素按照其显示顺序而组成的树,也是文档的可视化表示。它的做用是让您按照正确的顺序绘制内容。
WebKits RenderObject 类是全部渲染树的基类,其定义以下:
class RenderObject{ virtual void layout(); //布局 virtual void paint(PaintInfo); //绘制 virtual void rect repaintRect(); //从新绘制Rect Node* node; // DOM节点 RenderStyle* style; // 计算render style RenderLayer* containgLayer; //render layer }
渲染树是和 DOM 元素相对应的,但并不是一一对应。非可视化的 DOM 元素不会插入渲染树中,例如“head”元素。若是元素的 display 属性值为“none”,那么也不会显示在渲染树中(可是 visibility 属性值为“hidden”的元素仍会显示)。
关于多渲染树的例子是格式无效的 HTML。根据 CSS 规范,inline 元素只能包含 block 元素或 inline 元素中的一种。若是出现了混合内容,则应建立匿名的 block 渲染树,以包裹 inline 元素。
有一些渲染对象对应于 DOM 节点,但在树中所在的位置与 DOM 节点不一样。浮动定位和绝对定位的元素就是这样,它们处于正常的流程以外,放置在树中的其余地方,并映射到真正的框架,而放在原位的是占位框架。
建立完成渲染树时,并不包含位置和大小信息。计算这些值的过程称为布局或重排。
HTML 采用基于流的布局模型,这意味着大多数状况下只要一次遍历就能计算出几何信息。处于流中靠后位置元素一般不会影响靠前位置元素的几何特征,所以布局能够按从左至右、从上至下的顺序遍历文档。可是也有例外状况,好比 HTML 表格的计算就须要不止一次的遍历 (3.5)。
坐标系是相对于根框架而创建的,使用的是上坐标和左坐标。
布局是一个递归的过程。它从根渲染树(对应于 HTML 文档的 <html> 元素)开始,而后递归遍历部分或全部的框架层次结构,为每个须要计算的渲染树计算几何信息。
根渲染树的位置左上角 是 0,0
,(跟canvas2D坐标规则一致)其尺寸为视口(也就是浏览器窗口的可见区域)。
全部的渲染树都有一个layout
或者reflow
方法,每个渲染树将会调用其须要进行布局的子代的 layout
方法。
在绘制阶段,系统会遍历渲染树,并调用渲染树的paint
方法,将渲染树的内容显示在屏幕上。绘制工做是使用用户界面基础组件完成的。
绘制的顺序其实就是元素进入堆栈样式上下文的顺序;从后向前。块渲染树的堆栈顺序以下:
绘制实现可参考canvas
(canvas必定要学的啊 时刻关注一些前沿的动做
),了解基础图元绘制方法与过程。例如绘制line
(须要坐标 基础图元结构等等):
距离上一篇文章的生活日记: 20210521那天呢照样开心(朋友圈依旧不活跃)。20210522呢不开心。20210523也就是今天总的来讲过得去 并无学习。(劳逸结合 哈哈)
而后呢由于最近有人总微信我编程范式到底选择哪一种好一点呢? 我如今用的更可能是什么编程范式呢? 本身写代码维护起来好困难怎么办呢?... (作了好久的解答,应该记录下来提供给你们)下期JS引擎以前 我会把编程范式作一个简单介绍供你们参考 小小插曲(预计明天)。
加油!有问题请你们随时留言,看到必定会回复的。对于上篇补架构图...好吧是我鸽了 我看也没人催..懒得画了