How browsers work -Behind the scenes of modern web browsers 有空翻译一下这篇必读的文章 —浏览器到底是怎么工作的、浏览器的底层原理是啥、浏览器的工作原理 网上有很多译文,谁知道他们怎么搞出来的,我觉得他们肯定连幼儿园都没毕业,我幼儿园大班 ,我自己翻一遍 会结合资料去翻译,反正怎么翻的你自己脑补就完事了,关于缩写,只在第一次出现的时候标一下,一些东西知道的就补上别的详细的,不知道的咱也不能瞎扯
有些意译的会放上原文参考,有错的地方留言指正,及时更改, 感谢 如果想转请评论留个言并注明原博 @Sclifftop https://blog.csdn.net/S_clifftop/article/details/95994512 复制转载的记得常回来看看,因为我可能会增加东西便于进一步理解,包括有些地方会加些原文没有的概括,有些错的我可能会改正,请别误导别人,臭弟弟
之前node译成了结点,但我发现节点更适合,改蒙逼了,早知道就不译node了 有漏改或替换错的你知道就行了:结点(节点)== node 结点:本身不代表任何质点, 它们为只具几何意义的几何点 节点:没找到
请问csdn审核人员,文章哪个地方内容有涉及?请指出
目录
请问csdn审核人员,文章哪个地方内容有涉及?请指出
1、基本介绍
1.1、我们将要谈的浏览器
1.2、浏览器最主要的功能
1.3、浏览器的高级组成结构(注意,开始有内涵了)
1.4、组件之间是怎么关联的呢(你的器官是怎么联系的呢)
2、渲染引擎
2.1渲染引擎
2.2主流程
2.3主要使用的两个渲染引擎工作方式示意图
2.4解析
2.4.1 先从基本的解析来说
2.4.1.1 解析
2.4.1.2 翻译(Translation)
2.4.1.3 解析器的种类
2.4.1.4 自动生成解析器
2.4.2 HTML解析器
2.4.2.1 HTML语法定义
2.4.2.2 解析HTML的语法
2.4.2.3 解析HTML的DTD
2.4.2.4 DOM
2.4.2.5 解析算法
2.4.2.6 解析的第一个过程解析词的算法
2.4.2.7 解析的第二个过程Tree Construction(树先生)的算法
2.4.2.8 解析完了之后
2.4.2.9 看下浏览器怎么处理错误
2.4.3 CSS解析器
2.4.4 脚本和样式表的顺序
2.4.4.1 脚本
2.4.4.2 根据后面的内容解析并加载
2.4.4.3 样式表
2.5 渲染树
2.5.1 渲染树与DOM树的关系
2.5.2 构造树的流
2.5.3 样式计算过程
2.5.3.1 共享样式数据
2.5.3.2 Firefox规则树
2.5.3.2.1 分解为各种结构(structs)
2.5.3.2.2 使用规则树得到样式内容
2.5.3.3 更容易的匹配规则方法
2.5.3.4 规则的优先级
2.5.3.4.1 样式表的优先级
2.5.3.4.2 权重
2.5.3.4.3 对规则进行排序
2.5.3.5 渐进过程(Gradual process)
2.6 布局
2.6.1 “Dirty bit”系统(Dirty bit system)
2.6.2 整体布局和递增布局
2.6.3 异步布局和同步布局
2.6.4 优化
2.6.5 布局过程
2.6.6 宽度计算
2.6.7 换行
2.7 绘制(Painting)
2.7.1 整体方式和递增方式
2.7.2 绘制顺序
2.7.3 Firefox的显示列表
2.7.4 Webkit区域存储
2.8 动态修改
2.9 渲染引擎的线程
2.10 CSS2视图模型
2.10.1 The canvas
2.10.2 CSS盒子模型
2.10.3 元素位置方案(Positioning scheme)
2.10.4 盒子的类型
2.10.5 位置
2.10.5.1 相对(relative)
2.10.5.2 浮动 (float)
2.10.5.3 绝对和定位 (absolute、fixed)
2.10.6 层级
2.11 相关资料
1、基本介绍
网页浏览器无疑是使用最广泛的软件。接下来我将解释一下它是怎么工作的,下面会讲:当你输入google.com
后浏览器会怎么运行才能让你看到google的页面
1.1、我们将要谈的浏览器
目前大家使用最广泛的最主要有五款浏览器 —Internet Explorer
(微软的浏览器)、Firefox
(全称也可以说是Mozilla Firefox
,火狐)、Safari
(苹果浏览器,知道怎么读吗?别再“撒夫瑞”了,是“色” “发” “瑞”哟)、Chrome
(谷歌浏览器)、Opera
(欧朋)。 后面我将通过几款部分有开源的浏览器并结合一些例子来说明。 通过W3C(World Wide Web Consortium
,为了规范某些东西而设立的组织,规范什么俺也不用多说)的数据统计,我们知道火狐,Safari和谷歌浏览器的市场占有率已经达到了近六成(旧的占有率,现在是多少自己去查),所以开源浏览器已是市场不可缺的一部分。
1.2、浏览器最主要的功能
浏览器最主要的功能说白了就是显示出你想要的资源,也就里向服务器请求然后显示在浏览器窗口中。请求的资源最常使用的格式是HTML(Hyper Text Markup Language
超文本标记语言),其他也包括PDF(Portable Document Format
便携的文档格式),image(图片)等等。怎么获取它们呢?就是使用URL(Uniform resource Identifier
统一资源标志符)。
浏览器解析出HTML文件的规则在HTML和CSS(Cascading Style Sheets
,层叠样式表)中有规范说明。这些规范说明是W3C来统一的,最新的HTML版本是5,最新的CSS标准是CSS3。
之前的浏览器都想当老大,都想赚钱,部分规则统一,其他规则都乱七八糟,都有自己的标准。所以这个事很严重,对吧,但W3C不让你乱搞,所以他们相对之前老实了一点,大部分是一致的。
浏览器的界面大致都相同(反正都抄来抄去,也不能反人类,毕竟要恰饭),一般都有下面的几点:
地址栏
回退和前进(帅得不谈)
书签栏(帅得不谈+1)
刷新、暂停刷新、停止载入(帅得不谈+2)
主页(帅得不谈+n)
重点来了,浏览器界面没有规范说要怎么怎么样,但设计出来都一致,“这是经过多年,浏览器相互模仿而形成的良好实践”
(看见没有,抄袭用优美的话就这样说),HTML5没有规定浏览器界面必须有什么元素,所以你想加什么加什么(加个奶子)
1.3、浏览器的高级组成结构(注意,开始有内涵了)
浏览器主要的组成:
用户界面(就是上面提到的那些乱七八糟的,就是打开浏览器看到的)
浏览器引擎 — 用于查数据和呈现内容
渲染引擎 — 结果是给人看的,解析并显示请求的内容呈现到你美丽的辗庞前(解析呈现就完事)
网络 — 就是网络请求用的,很多协议,不懂就去看计算机网络原理
UI的后端(前面这个UI的后端
我为了保命用工具人翻的,所以翻译好坏都不关我滴事) — 绘制基本的部件,你看一个页面是整体,其实是一个又一个小窗口拼起来的,小窗口内填满自己的内容,底层是一些操作用户界面的接口
js解释器(javascript不是java,如果你不太清楚区别请合法上网搜) — 解析执行js代码
数据存储(这个帅得不谈,就是效率有点低) — 持久层,就是把数据存到本地,也是个数据库,只不过存储方式和容量不同(如果你开发游戏需要使用,那么我给你一个忠告,先读进内存再用)
看下图,不用再翻一遍了吧,还是再来一遍吧 注意了,Chrome每一个选项卡都是一个单独的进程,就像你一边浏览黄色网站,一边防着父母打开了一个学习的网页,以便迅速切换,你以为只是表面上的一个浏览器,实际他有俩(只是合并了),打开任务管理器就知道了(自己查任务管理器怎么打开的)。
1.4、组件之间是怎么关联的呢(你的器官是怎么联系的呢)
Firefox和Chrome都有一个特殊的实现方法,下面会谈。
2、渲染引擎
渲染引擎,渲染嘛,就是把请求的内容显示在浏览器上。
一般渲染引擎可以显示HTML,XML(Extensible Markup Language
,可扩展标记语言),和图片。如果你有安装各种其他插件的话,浏览器也可以显示其他的东西。如果你想显示PDF,那你可以安装PDF查看工具插件,其他什么看片插件啦,文明和谐插件啦自己去找。
2.1渲染引擎
我们说的这几个浏览器(Firefox、Chrome、Safari)底层其实用了不同的渲染引擎。
Firefox使用的是Gecko(网页排版引擎),“自制”的引擎,为什么加引号,因为这是它老大网景做的,它只是属于网景的一个组织,原文是"home made",你懂我意思吧。
Safari和Chrome使用的是Webkit,之前苹果寻思了半天,是抄Gecko(由网景开发)还是抄KHTML(由KDE开发),最后也不知道谁决定的就抄了后面这个然后加以改进,后面给的理由挺多:KHTML渲染速度快,结构清晰等等
但是后来KDE和苹果不和谐,具体发生了什么咱也不在现场,你问我我也不知道谁先动的手,(苹果开源Webkit之前是一直在修改KHTML的,但他改动完提交的代码是一次性提交,而且量很巨大,KDE整理起来就很烦,岔个话题,你像那种变量名同时用拼音和英文缩写,英文缩写还写错,又不加注释,最基本的都乱七八糟,那运行效率可想而知,最后还得重构,我头都能给他削肚子里),再后来苹果开源了Webkit(苹果终于开源了东西,之前只开源抄来的,这个是站在巨人肩膀上的抄)
KHTML最初用于Linux操作系统,后来也可以用在Mac和Windows上,想了解可以看下后面这个网站: Webkit
2.2主流程
渲染引擎先从网络层来获取所请求的内容,这些内容是8K以内,使用chunk传输编码,这个是一种数据传输的机制,不懂的去查一下,然后就是渲染出来,看下面这个图:
获取完内容先解析,解析后把CSS和DOM组合形成一个渲染树,然后步局计算每一个对象的准确的位置及大小,最后画就完事了(不是拿笔画) 再给你解释一遍:
渲染引擎先解析HTML,变为DOM节点,再解析CSS规则(还有三种引入方式,还记得吧,你不知道的话影响也不大,文章后面会说),然后组在一起就是渲染树
渲染树包含了很多矩形,这个矩形有各种各样的属性,也就是颜色,大小之类的。这些矩形最后会在屏幕上按各自的位置显示出来的,像那些display值为none的元素是不在里面的,但是注意了:visibility值为hidden的会在里面(只是看不见,但是会存在)
然后就是布局的过程:计算出每一个节点的精确位置,有布局的元素会进行位置偏移
接下来就是根据前一步使用UI后端来“画”出来
理解每一步挺重要的,浏览器为了更好的用户体验,渲染引擎会尽快的把它们都显示出来,它不是在所有内容接收后再布局计算显示,有一部分是在从获取数据的同时就开始渲染了
2.3主要使用的两个渲染引擎工作方式示意图
Webkit Gecko
从上面两张图的对比,可以看出来虽然有些词不同,但方式基本相同的 下面是两者之间的对比:
首先从“树”来说
Gecko把格式化的元素树称为框架树(Frame tree),其中每一个元素都是一个框架树
Webkit使用的是渲染树(Render tree)这个词,你也可以叫呈现树,是由一个个的渲染对象组成
然后是布局这方面
Gecko使用重排(Reflow)这个词
Webkit使用的是布局(Layout)
DOM树和样式的联系
Gecko在HTML和DOM树间多了一层内容池(Content Sink),你想翻成别的意思,什么内容下沉层乱七八糟的都没关系,只要知道他是创建DOM元素的一个工厂
Webkit在DOM树和样式间使用附加(Attachment)这个词
2.4解析
我先用一句话给你概括一下
怎么硕呢,所有的编译过程都是从解析源文件开始,词法分析就是分析源文件,转换成token(这个我不译了,你把他当专有名词,原词比译过来表达方式更好一些),所以词法分析器也称为tokenizer也是可以理解的
而语法分析呢,就把把词法分析后的token拿来,然后根据定义好的文法规则,进行归约(不懂这个词就往下看,我只是概括)
2.4.1 先从基本的解析来说
解析是渲染引擎非常重要的过程,下面我来慢慢说明
先不管原文,解析说白了就是翻译成机器可以理解的,这样它才能运行,原文写的是:解析表示的是把那一堆东西翻译成一种可以更好的结构,它可以被理解然后运行。解析出来的东西和原来的一样,只不过表现形式不同,可以叫那个东西为解析树,或者是语法树。
下面是举栗子— 如果你想解析“2+3-1”,看下图 看下应该就明白了,从左下方子节点开始,然后从左到右合并运算,如果你没学过算法设计(大致是这个名),可以去找一下,和二叉树差不多的规则。解析基于语法(Grammar)的规则,你可以解析的每一种格式都是由词汇表和语法规则组成。人类的语言和这种相差很大,所以不能用传统的解析方式来解析。
2.4.1.1 解析
解析可以分成两部分:词汇解析和语法解析
词汇解析(Lexical)是一个把一句分解的过程。从人类的语言方面举例就是把一句话拆成每一个字或词
语法解析(Syntax)是根据语法规则对分解的东西再进行分析
解析器把工作分为两个部分 :词汇分析器(Lexer,某些时候也称为Tokenizer)(也可以叫做分词器
)主要负责把一句话拆分,分出来的东西还得有实际意义(像那些空格,换行什么的就去掉)、解析器(Parser)负责分析文档结构。看下图嘛:
解析过程是一个重复的过程
解析器先会从词汇分析器(Lexer)中取出一个,然后和解析规则相匹配
如果成功配对,就~会加到解析树中
如果没有成功配对,就先存起来,一直查询匹配,直到找到。如果找完都没找到,那就是报个异常(exception),表示这一块东西无效,里面有错,像语法方面什么的
然后就是重复上面的过程,解完取,取完解,循环+10086,直到没得了
2.4.1.2 翻译(Translation)
通常情况下,解析树只是半成品,它还要进一步操作,再对其进行“翻译”,转成另一种格式,那就是机器码
2.4.1.3 解析器的种类
解析器有两种:从上到下和从下到上
自上而下的解析器会从高层结构开始,并匹配
自下而上的解析器就是上面那种语法规则,从低级开始,直到高级
看例子吧,直接说也看不懂(还是“2 + 3 -1”
):
从上而下的解析器会先识别“2 + 3”
做为一块(表达式),接下来会进一步判断“2 + 3 -1”
做为一块,这个过程就是与其他规则相匹配,但起点是最高级的规则
上自下而上的解析器将分析语句,直到规则匹配,然后用规则替换匹配的输入,这将持续到输入结束,部分匹配的表达式放在解析器堆栈上,也称作移位归约(Shift Reduce)解析器,因为输入是逐渐右移,逐渐合并减少
栈
输入
2 + 3 - 1
块
+ 3 - 1
块 操作符
3 - 1
表达式
- 1
表达式 操作符
1
表达式
1
2.4.1.4 自动生成解析器
有些工具是可以生成你需要的解析器,也可以叫它们小解析器们的爸爸 生成解析器的工具,他会根据你定义的规则来生成一个解析器(这个小解析器就会根据你要求来解析其他东西)
Webkit使用两种解析器生成器 —
Flex(生成词汇解析器,需要输入包含你自定义的正则表达式的文件)、Bision(生成词法解析器,需要输入BNF 格式的语句规则)
2.4.2 HTML解析器
HTML解析器就是把HTML解析成解析树
2.4.2.1 HTML语法定义
这个是由W3C组织来规定的,最新的是HTML5,去找吧少年
2.4.2.2 解析HTML的语法
在上面解析的介绍中,可以知道,语法规则可以使用BNF格式来自定义,但是对HTML来说不适用,定义出解析HTML的解析规则不太容易,所以不能使用这种方法,那怎么办,就有了DTD(Document Type Definition文档格式定义)
HTML和XML(可扩展标记语言)非常接近,对于XML,有很多解析XML的工具,然后XML还有一个变种XHTML,这个结合了XML还有HTML的一些其他的特性,HTML的规则相对宽松,你可以省略一些标记,可以不需要头和尾一定匹配(就是不必封闭起来),而XML就非常严格了
虽然只有这一点差别,但是这就使HTML使用非常广泛,对于开发者来说更加容易,不易出错,你可以漏掉东西但能运行,这也导致HTML解析起来不太容易,传统的解析工具根本不行,你看了头不能匹配尾,就没办法确定结束,你看了尾就可能找不到头,所以XML这类解析器不适用于HTML
2.4.2.3 解析HTML的DTD
HTML定义是DTD格式,这种格式曾用于定义SGML(Standard Generalized Markup language标准通用语言标准),这种格式包括元素所有的定义,像属性及其层级结构,所以HTML DTD不能制作上下文结合的语法
DTD也经过一了些修改,严格模式的只是单一遵循定义,而其他模式也能对旧浏览器的标记进行支持,目的是向后兼容,目前严格的DTD参考后面这个网站:http://www.w3.org/TR/html4/strict.dtd(能打开,莫慌)
2.4.2.4 DOM
输出树(也就是渲染树),包括了DOM元素和其属性,它是HTML文档和HTML元素对外部而做的对象表现,这个外部就是那些js什么的,树的根节点就是文档对象
DOM相对解析前的文档几乎是一对一的关系
又举栗子,这段代码解析后就是下面那个图:
< html>
< body>
< p>
Hello World
p>
< div> < img src = " example.png" /> div>
body>
html>
和HTML一样,W3C组织对DOM也有明确规定,看后面这个网站:http://www.w3.org/DOM/DOMTR ,网站有对操作文档的规定,HTML定义看这个网站:http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/idl-definitions.html
当我说“树包含DOM节点”,我的意思是由树是由继承DOM接口的元素组成的,浏览器内部使用拥有其他属性的接口
2.4.2.5 解析算法
由之前所说,HTML是不能被那些常规的解析器(自上而下或自下而上)解析,因为以下几点:
语言相对宽松
浏览器只有基本的容错能力,只能检测我们知道的HTML错误
解析过程是反复调用的,一般来说被解析的资源是不变的,是固定的那些,但是在HTML中是有脚本的,脚本会包括一些document.write
之类的方法,它是动态变化的,所以那些常规的解析方式严格来说只能解析刚开始输入的那些内容,后面的变化那些就完蛋辽
因为常规的解析器不能解析HTML,只能自己定制适合自己的解析器,“私人定制,天下无敌”,解析算法在HTML5中有详细说明
算法分为两个阶段:
解析词(Tokenization,我把这个名词译成一段过程,主要是让你明白),“解析词”的过程是词汇分析,解析输入的字符,HTML的字符包括:开始的标签(tag知道吧,像
)、结束的标签(像
)、属性名还有属性值
这个工具(tokenizer)先识别字符,然后交给Tree Construction(这个我不译了,你可以叫它树先生),Tree Construction获取后就会生成DOM
这也是个循环重复的过程,直到输入的字符全都搞完辽就停止辽
看下图(还用解释不,想的话评论留言我加上):
2.4.2.6 解析的第一个过程解析词的算法
这个算法输出的是HTML Token,算法做为状态机(开发的应该知道状态机吧,就是根据每个状态封装当前状态下要做的事,尤其是开发游戏的很了解)来进行,每个状态都会识别一个或多个字符,然后根据字符的结果来更新下一个状态,每一步都会受到当前识别字符的状态和Tree Construction的影响 ,一句话,因为算法太复杂,输入同一个字符根据当前的状态可能产生不同的结果
所以举个栗子给你看:
< html>
< body>
Hello world
body>
html>
结合上面的栗子我来说一哈: 这个算法里有几个状态,先说一部分:
Data state,数据状态(初始状态)
Tag open state,标记开启状态
Tag name state,获取标记名的状态
然后就是解析的过程,与下面的图一起看:
初始状态是数据状态(Data state,这个是默认的状态),当它读到“<”,就切换到标记开启状态(Tag open state),然后接着读取,如果是“a-z”这39 个英文字母,它就切换到获取标记名的状态(Tag name state),当再读到“>”,它就关闭,上面的栗子中
就是个标记
它关闭之后先提交,然后就切回数据状态(Data state),下面的
也是同样的操作
然后就开始读“H”,然后就是“e”,然后就是“l”……,直到读到“<”之前,它会先提交,然后切到标记开启状态(Tag open state),再往下读,读到“/”,它就会切换到获取标记名的状态(Tag name state),然后读到“>”就关闭,接下来就切回数据状态(Data state),下面的
和前面的一样
看下面的图,不懂英语看上面的字脑补我在你耳边缩话讲解:
2.4.2.7 解析的第二个过程Tree Construction(树先生)的算法
当有Tree Construction的时候,就开始创建DOM对象(Document object),接下来Tree Construction不断接收上一过程输出的结果,然后不断往DOM添加元素,除了往DOM里面添加,它也会把一些元素存到栈中,这个栈你可以当成临时的仓库,这里面的东西就是用来匹配一些没有关闭的标记等东西,很巧,Tree Construction也有一个状态机,你可以叫他“插入模式”(insertion modes)
还是看那个栗子:
< html>
< body>
Hello world
body>
html>
先说一点,这个插入模式是包括很多状态(“before html”,“before head”,“after head”,“before body”等等,这些我不译),别晕了,可以与下面的图结合着看
Tree Construction的输入就是上一过程的输出,他的第一个状态是“初始状态”(initial mode),接收HTML字符将会转为“before html”模式,然后处理这些字符,这个状态会在DOM根节点创建“HTMLHtmlElement”(没有写错,中间的Html换成Head或Body意会一下)
当收到
后就转为“before head”模式,,如果你不写
,它也会创建“HTMLHeadElement”,接下来会转为“in head”状态,然后的然后就是“after head”模式,(然后的同义词除了接下来还有哪个?)然后它创建“HTMLBodyElement”并转为“in body”模式
下一步,它不断收到“Hello world”的字符,当收到“H”它就会把“H”加到“Text”节点,后面的都会加进去,然后它收到
,就会转到“after body”模式,最后的最后它接收完了就会转到"after after body”模式,收到最后的字符它就会休息了
看下面的图,不懂英语看上面的字脑补我在你耳边缩话讲解:
2.4.2.8 解析完了之后
在这个阶段,浏览器标记DOM为“开放”状态,然后转译处于阻塞模式的脚本(js之类的,这些脚本需要在前面那些东西解析后执行,所以先排队等待),前面的“开放”状态会激活“complete”和“load”事件
想看上面两步解析的算法,可以看下这个网站嘛: http://www.w3.org/TR/html5/syntax.html#html-parser
2.4.2.9 看下浏览器怎么处理错误
你在浏览器中不会看到一些报错,是因为浏览器已经帮你“修复”了 看下这个栗子:
< html>
< mytag>
mytag>
< div>
< p>
div>
Really lousy HTML
p>
html>
上面的栗子有很多错,要是我我可能受不了,但是浏览器是我哥,它不仅能忍,它还能给你改过来
浏览器有对错误处理的能力,但是这个并没有在HTML中明确规定,就像它本来也没有去规范浏览器必须要书签、前进、后退这些按钮,但开发者都一致的加上了
你可以没说要有什么功能,但是我可以让它有,很强,就像你规定了人类菊花只能拉屎(好像也没人规定只能出不能进),但是……嗯,你一定想不到此洞还能包容万物,那句话怎么说“天腐成都,无1无靠,遍地飘0,看那一朵朵菊花爆满山,盛开在Gay们相爱的季节”,爱他就多买润滑油
HTML5也规定了一些必要的东西,Webkit也在HTML解析器类的开头总结写出来,不译了,自己看,求我也不译(我译):
The parser parses tokenized input into the document, building up the document tree. If the document is well-formed, parsing it is straightforward.
解析器解析内容输入到文档,构建出文档树。如果文档符合语法规则,就会很容易的解析出来
Unfortunately, we have to handle many HTML documents that are not well-formed, so the parser has to be tolerant about errors.
事实上(如果你和我纠结Unfortunately为什么译成事实上,那你直接走吧,别看了),我们处理的HTML文档一定程度上不符合语法规则,所以转译的同时还得去处理错误(容错)
We have to take care of at least the following error conditions:
我们得小心下面这几种错误的情况:
- The element being added is explicitly forbidden inside some outer tag.In this case we should close all tags up to the one, which forbids the element, and add it afterwards.
一些元素是不能被加到外部的tag中的,所以在一种情况下我们需要关闭所有的tag,那种情况就是禁止元素再被加进去
- We are not allowed to add the element directly. It could be that the person writing the document forgot some tag in between (or that the tag in between is optional).This could be the case with the following tags: HTML HEAD BODY TBODY TR TD LI (did I forget any?).
我们不被允许直接添加元素,可能开发者写文档时在中间漏写了一些tag(或许tag写不写都行),例如:HTML HEAD BODY TBODY TR TD LI(后面是作者开玩笑,问有没有漏举例)
- We want to add a block element inside to an inline element. Close all inline elements up to the next higher block element.
还有一种是我们想添加一个块元素到行内元素中, 关闭直到下一个更高的块元素的所有内联元素
- If this doesn't help, close elements until we are allowed to add the element or ignore the tag.
(这句你自己看,给你个机会)
下面看下Webkit的一些容错的栗子:
把
写成
,为了适配IE和Firefox,Webkit使用下面的代码改错,原文后面有一句:这些错误是静默处理的,不会展示给使用者
纠错代码:
if (t->isCloseTag(brTag) && m_document->inCompatMode()) {
reportError(MalformedBRError);
t->beginTag = true;
}
错误的表格,这种就是你瞎写,表套表,瞎弄,表1是你写的,表2是人家帮你改的,他会把里面的表弄到外面的表外面,让它们成为同级关系
错表格式
下面是帮你改后的表
纠错代码:
if (m_inStrayTableContent && localName == tableTag)
popBlock(tableTag);
嵌套形式的元素,如果一个套在另一个外面,那第二个就会无视
纠错代码:
if (!m_currentFormElement) {
m_currentFormElement = new HTMLFormElement(formTag, m_document);
}
过深的标签层次
www.liceo.edu.mx is an example of a site that achieves a level of nesting of about 1500 tags, all from a bunch of s.
We will only allow at most 20 nested tags of the same type before just ignoring them all together.
上面那个网站就是一个例子,里面大约包含了1500个嵌套标签,如果标签是相同的,那最多允许嵌套20个
纠错代码:
bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName){
unsigned i = 0;
for (HTMLStackElem* curr = m_blockStack;
i < cMaxRedundantTagDepth && curr && curr->tagName == tagName;
curr = curr->next, i++) { }
return i != cMaxRedundantTagDepth;
}
错误的结束标签
Support for really broken html.
We never close the body tag, since some stupid web pages close it before the actual end of the doc.
Let's rely on the end() call to close things.
为了能够运行错误的html,我们不会让关闭body的标签起作用
因为一些臭傻逼瞎写,在不该结束之前就乱加结束标签,所以当我们想结束的时候,我们会调用end()方法
纠错代码:(直接给return了有没有,你就别想着瞎加乱搞事)
if (t->tagName == htmlTag || t->tagName == bodyTag )
return;
2.4.3 CSS解析器
了解了HTML解析,那这个就好理解了,不同于HTML解析,CSS是上下文解析,可以使用上面说的那些解析器解析 看几个栗子,一些词汇的语法由正则表达式规范,不懂正则表达的先去看下,如下:
这部分不用看,只要会CSS就知道这什么意思了,不会的话你不结合其他的示例也看不懂,所以不会就去搞两个小Demo看下,秒懂
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}* 这个是标志符(identifier)的缩写,和类名(class name)差不多,使用的方法是:#id
句法使用BFN格式定义:
ruleset
: selector [ ',' S* selector ]*
'{' S* declaration [ ';' S* declaration ]* '}' S*
;
selector
: simple_selector [ combinator selector | S+ [ combinator selector ] ]
;
simple_selector
: element_name [ HASH | class | attrib | pseudo ]*
| [ HASH | class | attrib | pseudo ]+
;
class
: '.' IDENT
;
element_name
: IDENT | '*'
;
attrib
: '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
[ IDENT | STRING ] S* ] ']'
;
pseudo
: ':' [ IDENT | FUNCTION S* [IDENT S*] ')' ]
;
Explanation: A ruleset is this structure: (这个是使用的语法结构)
div.error , a.error {
color:red;
font-weight:bold;
}
div.error and a.error are selectors. The part inside the curly braces contains the rules that are applied by this ruleset. This structure is defined formally in this definition:
ruleset
: selector [ ',' S* selector ]*
'{' S* declaration [ ';' S* declaration ]* '}' S*
;
This means a ruleset is a selector or optionally number of selectors separated by a coma and spaces (S stands for white space). A ruleset contains curly braces and inside them a declaration or optionally a number of declarations separated by a semicolon. "declaration" and "selector" will be defined in the following BNF definitions.
2.4.3.1 Webkit的CSS解析器
Webkit使用Flex和Bison解析器生成器来生成CSS解析器,之前的章节有说到解析器介绍,Bison使用从下到上移位归约解析器,而火狐使用的是自上而下解析器。每个CSS文件会被解析成样式表对象,每个对象都包含了CSS规则,而CSS规则又包含了各个组件,还有组件的样式,看下图:
2.4.4 脚本和样式表的顺序
2.4.4.1 脚本
浏览器是同步的,程序员希望解析器读到
标签时就立刻解析脚本并运行,当运行脚本时会停止解析文档,当脚本没有包含在内部,会先从网络获取,这个过程也是同步的,获取的时候也会停止解析文档,这个规则一直都在,去看HTML4和5
当你使用“defer”,也就是
,它在获取脚本的时候不会停止解析文档,当从网络获取完之后,它不会马上解析运行脚本,会在解析文档完之后再开始
还有一个关键字“async”,写法
,它是从网络获取的时候,不会停止解析文档,获取完就马上解析运行脚本
2.4.4.2 根据后面的内容解析并加载
Webkit和Firefox都有这方面的优化,当执行脚本的时候,会分出另一个线程去解析文档剩余的部分,然后查找出需要从网络获取的内容,获取然后加载。获取的时候会使用平行的网络(parallel connection),所以速度会更快。
注意一下,推测解析只是解析所需要的东西并提前加载,并不会修改整个DOM树,DOM树是它老大解析器负责的(它不是“解析器”,它只是解析一部分,并不负责真正的DOM生成部分)
2.4.4.3 样式表
理论上来说,样式表并不会改变DOM树,所以不需要停止总进度来等待这个样式表的生成
但是有一个小问题,在文档解析的时候,脚本也在运行,它会去查询样式信息,如果样式还没有解析完成或者没有加载完成,那脚本就不会得到正确的结果,或者得到一个没有解析完的样式,这个问题产生的概率非常非常小,但它总归要发生,所以Firefox定了个规则:加载或者解析样式表的时候,停止脚本的运行,而Webkit做的是:如果脚本想获取的样式与未被加载的那些内容有关联,那就停止运行脚本
2.5 渲染树
当DOM树解析生成完之后,浏览器就会去生成另一个树 —
渲染树。
渲染树是为了更好的渲染显示出来,它是文档解析成一个视觉方面的效果(举个不恰当的例子,剧本拍成电影,导演脑子里先有的就是电影之前的效果,他这个根据剧本想出来的效果可能拍不出来,所以不太恰当),渲染树主要目的就是为了浏览器把各元素正确的渲染在该在的位置
Firefox把渲染树的元素称为“frames”(上面有说,看之前那个图),Wekit使用渲染器或渲染对象
渲染器知道如何布局并画出各个渲染节点中的内容
Webkit的渲染类如下:
class RenderObject{
virtual void layout ( ) ;
virtual void paint ( PaintInfo) ;
virtual void rect repaintRect ( ) ;
Node* node;
RenderStyle* style;
RenderLayer* containgLayer;
}
每个渲染器会绘出一个长方形的区域,相当于CSS盒子(CSS2中有定义,自己去看)它包括很多属性,像长、宽、位置等等,就是那些图形该有的属性,这个区域与样式中的属性相关联
下面是Webkit代码,根据显示的属性选择相应的渲染器:
RenderObject* RenderObject: : createObject ( Node* node, RenderStyle* style)
{
Document* doc = node-> document ( ) ;
RenderArena* arena = doc-> renderArena ( ) ;
. . .
RenderObject* o = 0 ;
switch ( style-> display ( ) ) {
case NONE:
break ;
case INLINE:
o = new ( arena) RenderInline ( node) ;
break ;
case BLOCK:
o = new ( arena) RenderBlock ( node) ;
break ;
case INLINE_BLOCK:
o = new ( arena) RenderBlock ( node) ;
break ;
case LIST_ITEM:
o = new ( arena) RenderListItem ( node) ;
break ;
. . .
}
return o;
}
元素的类型也不是瞎定义的,像表单控件和表这种就比较特殊
拿Webkit来说,如果想要渲染一个渲染树的节点就会重写上面的“createRenderer”方法,渲染器指向样式对象(样式对象包含各种非几何信息)
2.5.1 渲染树与DOM树的关系
渲染树的每个节点渲染器与DOM树的每个节点对应,但不是完全对应,一些不会在视觉上表现出来的DOM元素就不会添加到渲染树中,栗如,“none”属性的元素不会添加进去,但如果元素属性是“hidden”则会加进去
一部分DOM元素与可视对象一一对应。也有一些有复杂结构的元素不能被一个单独的渲染器渲染出来(Thease are usually elements with complex structure that cannot be described by a single rectangle),举个栗子,为了渲染“select”(选择列表),就会用到三个渲染器,一个是描绘显示的区域,一个是选择列表,还有一个是按钮。如果一行文本过长而换行,那多余的那些行也会有额外的渲染器来渲染
通过CSS的规定可以知道,一个内联元素必须包括块元素或内联元素。而且为了混合元素,将会创建一些匿名块渲染器来包装行内元素(anonymous block renders will be created to wrap the inline elements)
还有一些渲染对象与DOM树不同位置的DOM节点对应。有布局的元素(“float”、“absolutely”)会浮动出来,最终渲染在正确的位置,在没有真正渲染前,那个位置会先“规划”出来,先“占个位”(Floats and absolutely positioned elements are out of flow,placed in a diefferent place in the tree,and mapped to the real frame.A placeholder frame is where they should have been)
2.5.2 构造树的流
Firefox会注册一个“东西”(presentation,特么的这些专有名词译出来尬尬的,不译了)来监听DOM树的变化,如果DOM树变化,那这个“东西”会重新排列样式,并让“FrameConstructor”来创建一个“盒子”(frame,就是一个盒子一样的东西)
而在Webkit中,重排样式并且创建渲染器的称为“附加”(attachment),每一个DOM节点都会有个附加(attach)方法,附加的过程是同步过程,每个节点会调用attach
方法来插入DOM树
和
标签会加到渲染树的根节点,根节点渲染在CSS规定里面有说,也被称为包裹块(containing block)—包含别的块的最高级别块,它的尺寸是Viewport(这个不译,看上面那张图就知道了)的尺寸,也就是浏览器窗口的显示区域尺寸。Firefox称之为ViewPortFrame,Webkit称之为RenderView(这些名词不译),剩余的渲染树节点将会插入其中
2.5.3 样式计算过程
构建渲染树需要对每个要渲染对象的可见属性进行计算,这个过程在计算样式属性的时候就一块搞了
渲染对象的样式包括各种原始的样式表,内联样式以及HMTL可见的属性(像“bgcolor”这些),内联样式会转换并与CSS样式属性进行匹配
原始的样式表就是浏览器默认的样式,之后你也可以自定义(自定义喜欢的样式,Firefox的自定义会放在“Firefox Profile”文件夹内)
样式的计算会带来某些困难:
首先是存储方面:样式有非常多的属性,所以数据量有点大
表现方面:渲染树中每个元素都需要进行匹配规则,如果没有进行优化,那表现上就会出现问题,因为规则太多,一个还好,那所有的元素都匹配一遍就会gg,拿下拉列表来说,这玩意结构复杂所以不可行。看后面这个栗子 div div div div { }
,这个套了四层,假设想要检查规则是否适用于你想选择的那个,然后也选择了该节点的路径,但你第一次找的可能只有两个div(因为你的网页里面不可能只有四层div的结构),所以不得不继续再遍历去找其他符合的
规则涉及太多、层级太复杂,导致难以应用
下面是浏览器的解决办法:
2.5.3.1 共享样式数据
Webkit节点会引用样式的对象,在某些条件下这些对象可以共享,下面是可以共享需要的条件:
这些节点是“兄弟姐妹”关系(就是同级)
这些节点必须在同一鼠标状态下(如果一个是hover
,另一个必须也是hover
)
都没指定id
标签名要一样
类也要一样
属性要完全一样
链接的状态也要一样(参考上面的鼠标状态)
focus状态也要一样
不能被属性选择器影响,属性选择器就是一次性匹配一堆节点然后进行属性设置
没有写内联样式
没有同级选择器被使用,当有的话,WebCore会设置一个全局的开关来禁止样式的共享(包括相邻兄弟选择器,还有:first-child
和 :last-child
选择器)
2.5.3.2 Firefox规则树
为了简单样式的计算,Firefox有另外两个树 —规则树(rule tree)和样式内容树(style context tree),Webkit也有样式对象,但不是像Firefox这样存储在类似树的结构中,使用的是DOM节点指向关联的样式
下面是Firefox的style context tree:
样式内容包括最终值(end values,别说结束值呦,打你)。这些值是结合规则把所有逻辑值变为具体的值后计算出来的,举个樱桃,如果有一个逻辑值是节点某个属性,而且这个属性值是百分比,它会计算出这个节点属性绝对的值,规则树非常“聪明”,它会在节点内共享这些值,这样就不用重复计算了,也节省了空间
所有的匹配规则都存在树中,底部的节点有更高的优先级,如果有节点匹配规则它就会把其加进去,刚开始它不会计算匹配所有的节点,只有节点的样式需要被计算时,它才会把计算的路径加进树里,可以说相当懒
The idea is to see the tree paths as words in a lexicon(这句你自己去理解) 下面是已经计算好的路径:
结合上图说一下,如果我们想找B-E-I
这个规则,就可以直接在A-B-E-I-L
中找到,不用重新再去寻找,不用浪费不必要的“精力”
2.5.3.2.1 分解为各种结构(structs)
样式树分解成各种结构,这些结构包括某一类别的样式,像border、color等,结构中的属性包括继承的(如果节点的属性没有被定义,将会继承它们的父节点),非继承的(非继承的属性也可以叫做“reset”属性,指那些如果没有被定义,则会使用默认的值)
树缓存了全部的结构(包括计算的最终值),如果有一个节点不满足结构中的定义,那就会在高一级节点使用缓存的结构
2.5.3.2.2 使用规则树得到样式内容
当想要计算元素的样式内容,会首先算出所在的路径(或使用已有的路径),然后就会结合路径中的规则去完善(fill,你也可以说“填满”)样式内容的结构。
计算会从最高级节点开始,也就是最底部节点,然后向上遍历树,直到遍历完,如果某个节点A没有具体的结构说明,会继续向上找,直到找到最符合的,然后指向这个节点A(共享结构,这是最佳的方法),这样不用重新计算最终值,也节省了空间
如果没有找到,那就会使用上面说的继承,继承父节点,如果是reset结构,那就会使用非继承,也就是使用默认值
如果一个节点有计算值,那就会进一步操作,计算出最终值,然后缓存在父节点以便子节点使用
假如一个元素有相邻节点或者它的“兄弟”节点指向同一个父节点,那这个样式内容可以在它们之间共享(下面的
就是)
看下面的栗子,上面是THML,下面是CSS:
< html>
< body>
< div class = " err" id = " div1" >
< p>
this is a < span class = " big" > big error span>
this is also a
< span class = " big" > very big error span> error
p>
div>
< div class = " err" id = " div2" > another error div>
body>
html>
div { margin : 5px; color : black}
.err { color : red}
.big { margin-top : 3px}
div span { margin-bottom : 4px}
#div1 { color : blue}
#div 2 { color : green}
根据CSS可以看出,我们改的只有两个值,外边距(改了整个边距margin
、上边margin-top
、下边margin-bottom
)和颜色(也就是颜色)
下面是规则树(rule tree): 下面是结构树(context tree): 下面结合上面的规则树和结构树说下解析的过程:
先解析HTML,当解析到第二个创建样式环境并完善样式结构
为匹配规则时发现影响到的是1、2、6,有这么多就意味着已经有匹配的路径,就得再为规则6添加另一个节点(就是上面规则树的节点F)
创建完结构树的F就将新的样式环境指向规则树中的F(注意,两个F不是同一个)
因为节点F规则没有写外边框结构,因为我们向上找,如果有的话就继承使用(就是节点Bmargin:5px
)该节点的样式(会用CSS就很好了解,就是父节点的样式会影响到子节点,子节点单独有定义规则就用自己的规则,如果节点是reset
属性且没有定义规则就使用默认值)
该节点有写颜色样式,所以就不能使用父节点的样式,然后计算出该节点的RGB值,接下来缓存到该节点
对于第一个
,我们将会匹配规则然后指向规则树的G,因为有兄弟节点有同一父节点(可以共享父节点的样式内容),第二个
就更简单了,就可以直接指向前一个
结构(就是那一条条路径,里面包括节点)的样式可以继承父节点的(color属性也可以继承,但Firefox把它当成reset
然后缓存在规则树中)
如果我们修改
的规则为p {font-family:Verdana;font size:10px;font-weight:bold}
,那它的子节点就得使用同样的字体
Webkit中没有rule tree,匹配声明要经过4次判断,顺序如下:
高优先级的、不重要的(需要首先被声明的是那种被依赖的,像display)
高优先级的、重要的
普通优先级的、不重要的
普通优先级的、重要的
根据前面的优先顺序进行一次一次替代(The last wins,就是有规则的节点赛高)
2.5.3.3 更容易的匹配规则方法
几种CSS方法:
外部样式 p {color:bule}
内联样式
还有一种是直接用控件的属性名定义
后两种直接写进去了,不用再去查找节点进行匹配规则,所以比较快
但是因为一些缺点(上上上面有说),匹配CSS规则的过程非常麻烦,所以就做了如下的操作:
就是创建一堆表(map),解析完样式,根据选择器的不同,规则会被加进不同的哈希表(hash map)中,这个表有几类:id表、class表、tag表、还有一个表是如果不能匹配前面那几种就加进来。 如果选择器有id,规则会被加进id表中,如果有class名,将会加进class表中
这样就不需要查看声明了,可以直接在相关的表中取规则,这些表包含了超过95%的规则(This optimization eliminates 95+% of the rules,这种优化可以剔除至少95%的规则),所以在匹配的过程中就不需要再做很费时的操作,就很快
看下面这个栗子:
p.error { color : red}
#messageDiv { height : 50px}
div { margin : 5px}
CSS样式的第一行会被加进class表中,第二行会加进id表中,第三行加入tag表中
再看下一段HTML:
< p class = " error" > an error occurred p>
< div id = " messageDiv" > this is a message div>
首先为
寻找规则,会进入class表,找到p.error,然后下面的会在id表或tag表中找到,剩下的那些无非就是找出最最符合的然后提取出来
如果多加了一行下面规则:
table div { margin : 5px}
那就会在tag表中找,但是找不到,因为没有
很巧,Webkit和Firefox会做同样的这些步骤
2.5.3.4 规则的优先级
样式对象的属性(property)与每个可见的属性(attribute)对应(基本上的都是这样),如果属性没有被匹配的规则定义,就会从父节点继承,不能继承的有默认值
如果一个还好,当有多个那就会冲突,所以用优先级解决这个问题
2.5.3.4.1 样式表的优先级
一个控件(称节点什么的其实都“一样”,都对应同一个东西)的属性可能在好几个样式表中定义,也能在一个样式表中有多处定义,根据CSS2的定义,层级顺序(从低到高),如下:
浏览器默认值 Browser declarations(declaration
我暂译成值,你知道它表示什么就行了)
用户默认值 User normal declarations
开发者默认值 Author normal declarations
开发者优先值 Author important declarations
用户优先值 User important declarations
2.5.3.4.2 权重
原文写了很多,我找张图看下就好了,如下: 说明一下:
如果有!important
表示强制使用,是最高级,然后就是上面的顺序,权值越大级别越高
如果权重值加起来一样,那么后声明的比先声明的级别高
id是高于class的,所以再多的class权重值相加即使比id的权重值大也不会比id优先
emmmmm……
具体的还是要你们去深入学,其实规则也就那些,我写太多怕影响你们强大的学习能力,我就不写了
2.5.3.4.3 对规则进行排序
规则匹配后,根据层级规则排序,Webkit使用冒泡排序(bubble sort)小列表,使用归并排序(merge sort)大列表,Webkit会重写“>”操作符实现规则排序:
static bool operator > ( CSSRuleData& r1, CSSRuleData& r2)
{
int spec1 = r1. selector ( ) -> specificity ( ) ;
int spec2 = r2. selector ( ) -> specificity ( ) ;
return ( spec1 == spec2) : r1. position ( ) > r2. position ( ) : spec1 > spec2;
}
2.5.3.5 渐进过程(Gradual process)
Webkit使用一个标志来标记最高级的样式表(包括@import)被加载完,当附加(attach,Webkit专有的,开始有说)时样式没有完全被加载,会在那个地方加个占位,当样式加载完会重新计算一次
2.6 布局
当渲染器创建并加入树中,它还没有声明所在的位置和大小,计算这些值的过程称为layout(Webkit的叫法,刚开始有说,就是那张图)或reflow(Gecko的叫法)
HTML使用基于流的布局模型,意思就是每一次过程都在计算,而且后面的布局不会影响前面的,所以可以从左到右、从上到下进行布局
坐标系统是相对于根框架(最大的那个框架),会使用到Top
、Left
布局是一个递归的过程,从根渲染器(对应HTML根)开始布局,然后在各框架中循环并计算几何信息(就是位置、大小等这些值)
根渲染器是从(0,0)开始,大小就是窗口的尺寸(不是整个浏览器,是可显示的区域的尺寸)
所有的渲染器都有layout
或reflow
方法,每个渲染器布局时都可能调用到
2.6.1 “Dirty bit”系统(Dirty bit system)
一些小的改变就没必要重新布局,浏览器会使用到“Dirty bit”系统,如果有部分改动,渲染器会标记自身或子节点为“dirty”,就表示需要重新布局
有两种标记 — “嘤嘤嘤,我身体不干净了”(dirty)、“我孩子脏了,嘤嘤嘤”(children are dirty) 子节点脏表示尽管自己没变,但至少有一个子节点需要重新布局
2.6.2 整体布局和递增布局
有些情况会造成整体重新布局,这种称为整体布局(global layout),产生的原因如下:
Layout can be incremental, only the dirty renderers will be layed out (this can cause some damage which will require extra layouts),布局不仅有整体,也是可以递增的,只需要布局脏的那部分就行了(整体布局会有额外的布局,带来不需要的开销,所以不妥)
当渲染器“脏了“会触发递增布局(incremental layout),举个栗子,有额外的内容从网络获取被加进DOM树中,此时就会触发,这种是异步的
2.6.3 异步布局和同步布局
上面的递增布局是异步的。Firefox有一个队列叫“reflow commands”来放置递增布局并设置一个调度器来批处理队列中的命令。Webkit也有一个计时器来执行递增布局(遍历树并对脏渲染器重新布局)
脚本请求某些样式信息会同步触发递增布局,整体布局通常也是同步触发
有时候一些属性的改变会也重新布局,像列表滚动
2.6.4 优化
当窗口发生“变化”(他这边用的“resize”)或者节点发生变化(只是位置,没有尺寸变化),就不重新计算,会在缓存里去取值
这种优化在只修改子树且不发生整体布局变化,只是局部变化不影响周围的变化的情况下生效(例如:往输入框里输入字符),如果没有这种优化,那每输入一个字符就需要重新布局一次,那就太扯了 (In some cases - only a sub tree is modified and layout does not start from the root. This can happen in cases where the change is local and does not affect its surroundings - like text inserted into text fields [otherwise every keystroke would have triggered a layout starting from the root]. )
2.6.5 布局过程
布局有以下几个步骤:
父渲染器先决定宽度
然后父节点遍历子节点
放置子渲染器位置
计算子节点的高度,如果子节点是dirty 或者 整体布局变化 或 其他原因也会调用子节点的布局得到最终高度
得到全部子节点的高度算出自己整个的高度
将自己的dirty bit设为false,表示算完了,如果有改变再设true,由父的父节点调用
这个自己理解一下,是相对的,你是爸爸的同时也是儿子,你对儿子做的,你爸爸也会对你做同样的事 乖,叫爸爸
Firefox使用“state”对象(nsHTMLReflowState)作为布局参数,这个包括了父节点的宽度 Firefox布局输出是“metrics”对象(nsHTMLReflowMetrics),这个包括节点计算后的高度
2.6.6 宽度计算
渲染器宽度是根据容器宽度、渲染器样式宽度属性、外边距及边框
举个栗子:
< div style =" width : 30%" />
在Webkit中,上面这段计算方式(使用的是RenderBox类的calWidth方法)如下:
容器的宽度是容器的可用宽度的最大值,这里说的可用宽度指的是内容的宽度,由下面的过程计算出clientWidth() - paddingLeft() - paddingRight()
,clientWidth(或者是clientHeight,后面就改成高度)指的是对象除开边框和滚动条之外剩下的内部宽度
元素的宽度属性“witdh”,将会根据容器宽度的百分比算出实际的值
然后计算横向的边框和内边距并加进去
上面就是计算过程,最终得到最小和最大宽度,如果实际宽度大于最大宽度,就取最大宽度,如果小于最小,那就取最小宽度
这个宽度值是缓存起来的,如果宽度没有变化可以随时取用
2.6.7 换行
当渲染器要换行时,将会停止并告诉父节点“爸爸,俺要换行”
,父节点将会创建新的渲染器然后对换行部分进行布局
2.7 绘制(Painting)
在绘制阶段,渲染树会遍历然后调用paint
方法画出内容,使用UI基础控件绘制
2.7.1 整体方式和递增方式
和前面说的布局差不多,绘制也有整体绘制(就是绘制整个树)和递增绘制。
在递增绘制中,一些渲染器以不影响整个树的方式进行修改,这些渲染器会使它自己的区域无效,操作系统(OS)把那些区域当作脏区域(dirty region)然后触发“paint”事件,OS贼鸡儿聪明,鸡儿贼聪明,它会将几个区域合并成一个。
在Chrome中,这个比较复杂,因为渲染器处在不同进程中(除了主进程还有其他进程),在某种程度上Chrome模仿了OS的行为,监听事件然后发送消息给根节点渲染器 (render root,这是大总管,可以比作奥特之王,M78星云的王者 ,说到奥特之王那我就来说一说嗷,这个奥特之王年龄超过20万岁,他头部的球体可以接收宇宙中发生的所有的事(这要是给扣下来,得特么卖多少钱?),而且奥特之王有个很牛逼的技能:王者再生光线 ,这可是复活雷欧的光线,说到雷欧,我不得不多说几句,雷欧同志以前是咱L77星云的炎之战士,经过一系列事件后加入了党,尽职尽责,没事就欺负一下小怪兽,小日子过得美滋滋,他的变身器是戒指狮子之瞳,只要双手交叉然后上举,接下来大喊一声我党万岁 “雷特么欧”,就可以变身,与巴啦啦小魔仙变身方式比稍微不那么华丽(巴啦啦魔仙变身方式多帅多华丽啊,宇宙最高但雨女无瓜),他的腿技非常厉害,什么腿切,背踢,最强必杀技就是雷欧飞踢,吊的一批,接着再说奥特之王,他的另一个技能是bug般的存在:王者变革,可以与宇宙融合,靠这一招拯救宇宙你敢信?反正也是吊的一批) 同志们回来回来,接着上面的render root,它将会重绘自己(不过经常是子节点)
2.7.2 绘制顺序
CSS2定义了绘制过程的顺序,看后面这个 http://www.w3.org/TR/CSS21/zindex.html 元素会先放在stacking contexts,放置的顺序会影响到绘制
一个块渲染器的放置顺序如下(这个不译,都懂):
background color
background image
border
children
outline
2.7.3 Firefox的显示列表
Firefox遍历渲染树然后会为每一个绘制的区域(rectangular)创建一个显示列表,这个列表里面包括此区域绘制的顺序
通过这种方式重绘就不需要再次遍历渲染树来获取绘制顺序
Firefox不会把那些要隐藏的元素加进去(例如在其他不透明元素下的元素)
2.7.4 Webkit区域存储
绘制前,Webkit会将旧的绘制区域存为位图,然后只绘制新的与旧的之间的交叉的区域(It then paints only the delta between the new and old rectangles)
2.8 动态修改
浏览器会做尽可能小的修改来改变,所以如果改变元素的颜色不会重绘元素,改变元素的位置将会重新布局子节点然后重新绘制,添加一个DOM节点将会布局并重绘该节点
那些影响大的修改,例如修改整体字体大小,将会使之前的缓存失效,重新布局整个树并绘制
2.9 渲染引擎的线程
渲染引擎是串行的,除了网络外,都是单线程的。
在Firefox和Safari浏览器中,这个线程就指的是主线程
而在Chorme浏览器中,是选项卡进程的主线程(因为每一个选项卡就是一个进程,最最最最开始有说)
网络方面的是通过并行的线程进行操作,而且并行的连接是有限制的(通常是2-6个,Firefox 3使用的6个)
2.9.1 事件循环
浏览器主线程是一个事件循环,它无限循环以确保进程保持工作状态,事件是依次执行的(处理过之前的才能处理后面的)
下面是Firefox的主事件循环代码:
while ( ! mExiting)
NS_ProcessNextEvent ( thread) ;
2.10 CSS2视图模型
注意:我译的这篇是很早之前的了,虽然CSS3与CSS2相比添加新的功能或者完善部分定义,修改的挺多的,但是下面说的是基本的,还是要看,其他新增或修改的你自己去找
2.10.1 The canvas
根据CSS2的定义,canvas描述为“渲染格式化的结构的容器”(the space where the formatting structure is rendered)—也就是浏览器显示内容的区域
理论上canvas可以是无限大,但浏览器取初始的长宽值来设置canvas的大小,你家浏览器很大的话那你很牛批(交个朋友 )
根据 http://www.w3.org/TR/CSS2/zindex.html ,如果一个canvas嵌在另一个canvas中,就会把前者设为透明,否则就会设置一个默认的颜色
2.10.2 CSS盒子模型
所谓的CSS盒子模型(CSS box model)就是用来放置元素的长方形盒子,把抽象的事物具体化表述
每个盒子都有一个放置内容的区域(栗如:text、image等等),这个内容区域会被padding、margin、border等样式环绕(如果有设置的话),看下面的图就了解了,不用多说
下面就是盒子模型(CSS2): デスノート
2.10.3 元素位置方案(Positioning scheme)
下面说的对象、元素、DOM树结点你可以当成一个东西来理解
有三种方案:
Normal - 根据本身的位置来放置对象,意思就是对象在渲染树中的位置与DOM树中的位置相同
Float - 对象先按Normal方式布局,然后根据设置的位置进行浮动
Absolute - 对象在渲染树中的位置与DOM树中的位置不同
元素的位置会结合position和float属性得出
static和relative会在默认的文档流中
absolute和fixed会有一个绝对的位置
如果没有定义位置信息,那默认的就是static,剩下那几种需要结合位置(top、bottom、left、right)信息使用 盒子的布局会根据下面得出:
盒子类型
盒子的尺寸
上面的位置方案
外部的信息(例如图的大小、屏幕的大小)
2.10.4 盒子的类型
我直接在下面两句总结,后面说的那些就不写了,都是一个意思 块盒子(block box) - 这种是竖向排列的,它会独占一行,没有设置的话宽度默认占满父元素,设置宽度也是独占一行(一些刚学CSS的同学在想设置宽度怎么还是独占一行呢,有这种类似的骚想法很正常,吃一堑长一智) 内联盒子(inline box )- 这种是模向排行,直到一行放不下才会换行,它的宽度与其内的元素有关,设置宽高是没用的,而且边框的话只有left,right有效,像padding-top,padding-bottom是没用的
2.10.5 位置
2.10.5.1 相对(relative)
相对位置 - 很好理解,相对哪个元素,距离那个元素多远
看下面的栗子:
2.10.5.2 浮动 (float)
浮动的盒子就是在一行内向左或向右浮动
看下面的栗子(这个是图片向右浮动,看起来有一种inline-box的效果,具体的自己去查):
< p>
< img style =" float : right" src = " images/image.gif" width = " 100" height = " 100" > Lorem ipsum dolor sit amet, consectetuer...
p>
2.10.5.3 绝对和定位 (absolute、fixed)
这两种已经飞升了,不在文档流中
absolute相对的是非static的父类元素,没找到就一直找爸爸的爸爸的爸爸,直到body
fixed是相对窗口,如果有滚动条,滚动的时候,这个元素是不跟着动的
2.10.6 层级
CSS的z-index属性决定层级
盒子是叠在一起的(称为堆叠环境),先画的在下面,后画的在上面,上面的会盖住下面的
如果z-index没有指定,那后画的元素在上面,如果指定了,z-index值越大的越在上面
看下面的栗子:
< STYLE type = " text/css" >
div {
position : absolute;
left : 2in;
top : 2in;
}
STYLE>
< P>
< DIV
style =" z-index : 3; background-color : red; width : 1in; height : 1in; " >
DIV>
< DIV
style =" z-index : 1; background-color : green; width : 2in; height : 2in; " >
DIV>
p>
2.11 相关资料
Browser architecture
Grosskurth, Alan. A Reference Architecture for Web Browsers.
Parsing
Aho, Sethi, Ullman, Compilers: Principles, Techniques, and Tools (aka the “Dragon book”), Addison-Wesley, 1986
Rick Jelliffe. The Bold and the Beautiful: two new drafts for HTML 5
Firefox
L. David Baron, Faster HTML and CSS: Layout Engine Internals for Web Developers.
L. David Baron, Faster HTML and CSS: Layout Engine Internals for Web Developers(Google tech talk video).
L. David Baron, Mozilla’s Layout Engine.
L. David Baron, Mozilla Style System Documentation.
Chris Waterson, Notes on HTML Reflow.
Chris Waterson, Gecko Overview.
Alexander Larsson, The life of an HTML HTTP request.
Webkit
David Hyatt, Implementing CSS(part 1).
David Hyatt, An Overview of WebCore.
David Hyatt, WebCore Rendering.
David Hyatt, The FOUC Problem.
W3C Specifications
HTML 4.01 Specification.
HTML5 Specification.
Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification.
Browsers build instructions
Firefox.
Webkit.
译完了,我透。
你可能感兴趣的:(Browser,browser原理,中文翻译,今天天气晴,how,browsers,work,浏览器工作原理)
扫地机类清洁产品之直流无刷电机控制
悟空胆好小
清洁服务机器人 单片机 人工智能
扫地机类清洁产品之直流无刷电机控制1.1前言扫地机产品有很多的电机控制,滚刷电机1个,边刷电机1-2个,清水泵电机,风机一个,部分中高端产品支持抹布功能,也就是存在抹布盘电机,还有追觅科沃斯石头等边刷抬升电机,滚刷抬升电机等的,这些电机有直流有刷电机,直接无刷电机,步进电机,电磁阀,挪动泵等不同类型。电机的原理,驱动控制方式也不行。接下来一段时间的几个文章会作个专题分析分享。直流有刷电机会自动持续
基于社交网络算法优化的二维最大熵图像分割
智能算法研学社(Jack旭)
智能优化算法应用 图像分割 算法 php 开发语言
智能优化算法应用:基于社交网络优化的二维最大熵图像阈值分割-附代码文章目录智能优化算法应用:基于社交网络优化的二维最大熵图像阈值分割-附代码1.前言2.二维最大熵阈值分割原理3.基于社交网络优化的多阈值分割4.算法结果:5.参考文献:6.Matlab代码摘要:本文介绍基于最大熵的图像分割,并且应用社交网络算法进行阈值寻优。1.前言阅读此文章前,请阅读《图像分割:直方图区域划分及信息统计介绍》htt
Day1笔记-Python简介&标识符和关键字&输入输出
~在杰难逃~
Python python 开发语言 大数据 数据分析 数据挖掘
大家好,从今天开始呢,杰哥开展一个新的专栏,当然,数据分析部分也会不定时更新的,这个新的专栏主要是讲解一些Python的基础语法和知识,帮助0基础的小伙伴入门和学习Python,感兴趣的小伙伴可以开始认真学习啦!一、Python简介【了解】1.计算机工作原理编程语言就是用来定义计算机程序的形式语言。我们通过编程语言来编写程序代码,再通过语言处理程序执行向计算机发送指令,让计算机完成对应的工作,编程
git - Webhook让部署自动化
大猪大猪
我们现在有一个需求,将项目打包上传到gitlab或者github后,程序能自动部署,不用手动地去服务器中进行项目更新并运行,如何做到?这里我们可以使用gitlab与github的挂钩,挂钩的原理就是,每当我们有请求到gitlab与github服务器时,这时他俩会根据我们配置的挂钩地扯进行访问,webhook挂钩程序会一直监听着某个端口请求,一但收到他们发过来的请求,这时就知道用户有请求提交了,这时
百善孝为先
杜友顺
2018年11月29日天气~晴星期四找点空闲找点时间领着孩子常回家看看带上笑容带上祝福陪同爱人常回家看看家,永远是儿女们幸福温暖的港湾,那里有我们日夜思念的父母,有着彼此的牵挂,无论走到哪里,家永远是避风雨的港湾。今天没事,和媳妇回了趟老家,看看父母,回到家,房间里不算凌乱,可是细心的我发现有的地方已经沾满了灰尘,桌子上父亲不离手的烟灰缸也弹满了烟灰。几个马上就要腐烂掉的水果蔫耷的搭拉着脑袋躺在了
ARM驱动学习之基础小知识
JT灬新一
ARM 嵌入式 arm开发 学习
ARM驱动学习之基础小知识•sch原理图工程师工作内容–方案–元器件选型–采购(能不能买到,价格)–原理图(涉及到稳定性)•layout画板工程师–layout(封装、布局,布线,log)(涉及到稳定性)–焊接的一部分工作(调试阶段板子的焊接)•驱动工程师–驱动,原理图,layout三部分的交集容易发生矛盾•PCB研发流程介绍–方案,原理图(网表)–layout工程师(gerber文件)–PCB板
Faiss:高效相似性搜索与聚类的利器
网络·魚
大数据 faiss
Faiss是一个针对大规模向量集合的相似性搜索库,由FacebookAIResearch开发。它提供了一系列高效的算法和数据结构,用于加速向量之间的相似性搜索,特别是在大规模数据集上。本文将介绍Faiss的原理、核心功能以及如何在实际项目中使用它。Faiss原理:近似最近邻搜索:Faiss的核心功能之一是近似最近邻搜索,它能够高效地在大规模数据集中找到与给定查询向量最相似的向量。这种搜索是近似的,
2018-12-16
宝妈林秀云
2018年12月16日星期日天气晴本来今天是要参加读经班的,小宝贝昨天晚上突然发烧了,所以就没办法参加。同时今天也是小宝贝的生日,因为发烧她爸爸就不买蛋糕给她过生日了。就给她买了榴莲披萨当蛋糕。姐姐还为她做了生日贺卡,这个生日贺卡姐姐可是花了很长时间才完成的。吃完披萨准备上楼了,这时杨欣也想跟我们一起上楼,就被奶奶叫住说:“不要上楼了要准备睡觉了”。本来我想小宝贝可能会吵着跟杨欣一起玩。出乎我的意
ES聚合分析原理与代码实例讲解
光剑书架上的书
大厂Offer收割机 面试题 简历 程序员读书 硅基计算 碳基计算 认知计算 生物计算 深度学习 神经网络 大数据 AIGC AGI LLM Java Python 架构设计 Agent 程序员实现财富自由
ES聚合分析原理与代码实例讲解1.背景介绍1.1问题的由来在大规模数据分析场景中,特别是在使用Elasticsearch(ES)进行数据存储和检索时,聚合分析成为了一个至关重要的功能。聚合分析允许用户对数据集进行细分和分组,以便深入探索数据的结构和模式。这在诸如实时监控、日志分析、业务洞察等领域具有广泛的应用。1.2研究现状目前,ES聚合分析已经成为现代大数据平台的核心组件之一。它支持多种类型的聚
2022-08-28
蔚蓝一片晴
初三暑假培训收获点滴从8月25至8月27日三天两晚的培训结束了,回到家中,该静下心来整理一下触动心灵的收获,成为成长的积淀。1.在优秀团队中快速成长与提升,做一名反思成长型教师一名专业型教师的教学指导包括了教学原理知识、案例知识、策略知识。面对教学中的遇到的有趣的情形、问题会去研究其理,寻找更好的教法学法对策。从新手到成熟型教师,再走向专业型教师,需要的是觉醒与反思,多进行案例研究,从案例中观察、
STM32中的计时与延时
lupinjia
STM32 stm32 单片机
前言在裸机开发中,延时作为一种规定循环周期的方式经常被使用,其中尤以HAL库官方提供的HAL_Delay为甚。刚入门的小白可能会觉得既然有官方提供的延时函数,而且精度也还挺好,为什么不用呢?实际上HAL_Delay中有不少坑,而这些也只是HAL库中无数坑的其中一些。想从坑里跳出来还是得加强外设原理的学习和理解,切不可只依赖HAL库。除了延时之外,我们在开发中有时也会想要确定某段程序的耗时,这就需要
2020-8-19晨间日记:看过的电影
盐大虾
今天是周三起床:6点半就寝:11点天气:晴心情:正常纪念日:周三任务清单今日完成的任务,最重要的三件事:1.整理写过的文档2.电影《电灯泡》3.这就是街舞第三季第五期改进:早睡早起习惯养成:早睡早起,看书周目标·完成进度两篇文章学习·信息·阅读电影艺术发展史相关教材健康·饮食·锻炼吃了挺多零食,还喝了果粒橙,还是得少吃,多锻炼,不然会慢慢死掉的。人际·家人·朋友淡定交流,不放在心上。工作·思考专心
第1步win10宿主机与虚拟机通过NAT共享上网互通
学习3人组
大数据 大数据
VM的CentOS采用NAT共用宿主机网卡宿主机器无法连接到虚拟CentOS要实现宿主机与虚拟机通信,原理就是给宿主机的网卡配置一个与虚拟机网关相同网段的IP地址,实现可以互通。1、查看虚拟机的IP地址2、编辑虚拟机的虚拟网络的NAT和DHCP的配置,设置虚拟机的网卡选择NAT共享模式3、宿主机的IP配置,确保vnet8的IPV4属性与虚拟机在同一网段4、ping测试连通性[root@localh
5分钟说透AppStore审核原理,让你拥有上架新思路!
Q仔本人噢
在AppStore上架是越来越难了!相信非常多公司的技术人员都为此困扰,然而外包团队水平又层次不齐,容易遇坑,实在是内忧外患。是什么原因导致审核机制频繁调整?又是什么原因使得审核变得越发严格?那么接下来听小Q分解,马上给各位带来解答!首先看一下近一年的上下架的情况:近一年上架情况近一年下架情况通过数据我们发现越是马甲包产量权重高的分类里被下架的app数量越多,苹果此举可谓是上有政策,下有对策。通过
2019-03-24
李飞720
姓名:李飞企业名称:临沂鑫道食品有限公司组别373期利他1组日精进打卡第338天】【知~学习】1、阿米巴经营一段2、活用人才1段3、活法、一段【行~实践】一、修身:读书、抽烟减量、俯卧撑个跑步3公里二、齐家、劝说老爸与姑姑和好三、建功、业务洽谈【经典名句分享】1、依据原理原则追求事物的本质,以“作为人,何谓正确”进行判断2、经营者必须为员工物质和精神两方面的幸福殚精竭虑,倾尽全力,必须超脱私心,让
2019年8月6日 星期二 晴
李佳晨宝宝
今天我写完作业以后,我玩儿了一会儿我的拼装玩具,拼装玩具是我的世界的游戏里面的乐高,我拿出乐高把它拼成上次的迷宫,然后又给他升级了一下,我拆出上面一些部分的零件加大了游戏的难度,然后我又做了一个小牛圈。这个小牛圈里面住的是猪和牛,还有羊,给那里摆了一块草地,他们想吃东西直接在草地上吃,然后我把牛圈建了一个遮阳伞,防止天气太热把它们晒死。然后这样我的小牛就万无一失了,我再看看加大难度后的迷宫,实在是
计算机木马详细编写思路
小熊同学哦
php 开发语言 木马 木马思路
导语:计算机木马(ComputerTrojan)是一种恶意软件,通过欺骗用户从而获取系统控制权限,给黑客打开系统后门的一种手段。虽然木马的存在给用户和系统带来严重的安全风险,但是了解它的工作原理与编写思路,对于我们提高防范意识、构建更健壮的网络安全体系具有重要意义。本篇博客将深入剖析计算机木马的详细编写思路,以及如何复杂化挑战,以期提高读者对计算机木马的认识和对抗能力。计算机木马的基本原理计算机木
在RabbitMQ中四种常见的消息路由模式
Xwzzz_
rabbitmq 分布式
1.Fanout模式Fanout模式的交换机是扇出交换机(FanoutExchange),它会将消息广播给所有绑定到它的队列,而不考虑消息的内容或路由键。工作原理:生产者发送消息到FanoutExchange。FanoutExchange会将消息广播给所有绑定到它的队列,所有绑定的队列都会收到这条消息。消费者监听绑定的队列,处理收到的消息。特点:没有路由键:消息不需要路由键,所有绑定的队列都会接收
C++八股
Petrichorzncu
八股总结 c++ 开发语言
这里写目录标题C++内存管理C++的构造函数,复制构造函数,和析构函数深复制与浅复制:构造函数和析构函数哪个能写成虚函数,为什么?C++数据结构内存排列结构体和类占用的内存:==虚函数和虚表的原理==虚函数虚表(Vtable)虚函数和虚表的实现细节==内存泄漏==指针的工作原理函数的传值和传址new和delete与malloc和freeC++内存区域划分C++11新特性C++常见新特性==智能指针
放松的一天
4da9b7687fa0
20190325总结起床07:20图片发自App睡觉:23:00天气:晴今日任务清单学习·信息·阅读•水滴阅读Day40Alice’sAdventuresinWonderlandChapter6.2图片发自App•BBC跟读训练营Day24图片发自App图片发自App图片发自App•潘多拉口语训练营Day6Wow.Whatabigboy!•文化知识学习今日无•阅读时间地狱健康·饮食·锻炼•饮食目标
[Unity]在场景中随机生成不同位置且不重叠的物体
Bartender_Jill
Graphics图形学笔记 unity 游戏引擎 动画
1.前言最近任务需要用到Unity在场景中随机生成物体,且这些物体不能重叠,简单记录一下。参考资料:Howtoensurethatspawnedtargetsdonotoverlap?2.结果与代码结果如下所示:代码如下所示:usingSystem.Collections.Generic;usingUnityEngine;namespaceAssets.Scripts{publicclassNew
Spring Boot中实现跨域请求
BABA8891
spring boot 后端 java
在SpringBoot中实现跨域请求(CORS,Cross-OriginResourceSharing)可以通过多种方式,以下是几种常见的方法:1.使用@CrossOrigin注解在SpringBoot中,你可以在控制器或者具体的请求处理方法上使用@CrossOrigin注解来允许跨域请求。在控制器上应用:importorg.springframework.web.bind.annotation.
WebMagic:强大的Java爬虫框架解析与实战
Aaron_945
Java java 爬虫 开发语言
文章目录引言官网链接WebMagic原理概述基础使用1.添加依赖2.编写PageProcessor高级使用1.自定义Pipeline2.分布式抓取优点结论引言在大数据时代,网络爬虫作为数据收集的重要工具,扮演着不可或缺的角色。Java作为一门广泛使用的编程语言,在爬虫开发领域也有其独特的优势。WebMagic是一个开源的Java爬虫框架,它提供了简单灵活的API,支持多线程、分布式抓取,以及丰富的
vue+el-table 可输入表格使用上下键进行input框切换
以对_
vue学习记录 vue.js javascript 前端
使用上下键进行完工数量这一列的切换-->//键盘触发事件show(ev,index){letnewIndex;letinputAll=document.querySelectorAll('.table_inputinput');//向上=38if(ev.keyCode==38){if(index==0){//如果是第一行,回到最后一个newIndex=inputAll.length-1}elsei
《 C++ 修炼全景指南:十 》自平衡的艺术:深入了解 AVL 树的核心原理与实现
Lenyiin
C++ 修炼全景指南 技术指南 c++ 数据结构 stl
摘要本文深入探讨了AVL树(自平衡二叉搜索树)的概念、特点以及实现细节。我们首先介绍了AVL树的基本原理,并详细分析了其四种旋转操作,包括左旋、右旋、左右双旋和右左双旋,阐述了它们在保持树平衡中的重要作用。接着,本文从头到尾详细描述了AVL树的插入、删除和查找操作,配合完整的代码实现和详尽的注释,使读者能够全面理解这些操作的执行过程。此外,我们还提供了AVL树的遍历方法,包括中序、前序和后序遍历,
非对称加密算法原理与应用2——RSA私钥加密文件
私语茶馆
云部署与开发 架构及产品灵感记录 RSA2048 私钥加密
作者:私语茶馆1.相关章节(1)非对称加密算法原理与应用1——秘钥的生成-CSDN博客第一章节讲述的是创建秘钥对,并将公钥和私钥导出为文件格式存储。本章节继续讲如何利用私钥加密内容,包括从密钥库或文件中读取私钥,并用RSA算法加密文件和String。2.私钥加密的概述本文主要基于第一章节的RSA2048bit的非对称加密算法讲述如何利用私钥加密文件。这种加密后的文件,只能由该私钥对应的公钥来解密。
为什么学生不喜欢上学
虾虾说
图片发自App《为什么学生不喜欢上学》作者是丹尼尔·威林厄姆。本书从认知心理学角度,结合大量实证案例,阐释了大脑工作的基本原理,回答了关于学习过程的一系列问题。为什么学生不喜欢上学?——大脑工作的基本原理思考是缓慢的、费力的、不可靠的。思考有三个要素,环境、工作记忆和长期记忆。环境是信息来源;长期记忆是知识、经验的巨型仓库,随时可以调取;工作记忆是中央处理器,是加工信息素材的中央厨房,也是思考过程
补充元象二面
Redstone Monstrosity
前端 面试
1.请尽可能详细地说明,防抖和节流的区别,应用场景?你的回答中不要写出示例代码。防抖(Debounce)和节流(Throttle)是两种常用的前端性能优化技术,它们的主要区别在于如何处理高频事件的触发。以下是防抖和节流的区别和应用场景的详细说明:防抖和节流的定义防抖:在一段时间内,多次执行变为只执行最后一次。防抖的原理是,当事件被触发后,设置一个延迟定时器。如果在这个延迟时间内事件再次被触发,则重
2022-07-06学会放手
杨晓玲乐平市第十一小学
2022年7月5日星期一晴今天结束了国培培训,上午收拾好物品,带着孩子整理心情,带着憧憬去到孩子新的学校,因为从小我有意培养孩子自己整理自己内务,孩子很认真的把自己要用的都整理好,不用的都另外装好,这一点孩子的能力还是挺强的。把自己的行李按学校提出的要求认真的整理好,我们便出发了。我们早早的来到学校,时间还早,便让她到阿姨那休息了一会儿,每去到一个新的地方,能迅速的安顿下来,这是非常好的。时间很快
《 C++ 修炼全景指南:四 》揭秘 C++ List 容器背后的实现原理,带你构建自己的双向链表
Lenyiin
技术指南 C++ 修炼全景指南 c++ list 链表 stl
本篇博客,我们将详细讲解如何从头实现一个功能齐全且强大的C++List容器,并深入到各个细节。这篇博客将包括每一步的代码实现、解释以及扩展功能的探讨,目标是让初学者也能轻松理解。一、简介1.1、背景介绍在C++中,std::list是一个基于双向链表的容器,允许高效的插入和删除操作,适用于频繁插入和删除操作的场景。与动态数组不同,list允许常数时间内的插入和删除操作,支持双向遍历。这篇文章将详细
Java序列化进阶篇
g21121
java序列化
1.transient
类一旦实现了Serializable 接口即被声明为可序列化,然而某些情况下并不是所有的属性都需要序列化,想要人为的去阻止这些属性被序列化,就需要用到transient 关键字。
escape()、encodeURI()、encodeURIComponent()区别详解
aigo
JavaScript Web
原文:http://blog.sina.com.cn/s/blog_4586764e0101khi0.html
JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:,decodeURI,decodeURIComponent 。
下面简单介绍一下它们的区别
1 escape()函
ArcgisEngine实现对地图的放大、缩小和平移
Cb123456
添加矢量数据 对地图的放大、缩小和平移 Engine
ArcgisEngine实现对地图的放大、缩小和平移:
个人觉得是平移,不过网上的都是漫游,通俗的说就是把一个地图对象从一边拉到另一边而已。就看人说话吧.
具体实现:
一、引入命名空间
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Controls;
二、代码实现.
Java集合框架概述
天子之骄
Java集合框架概述
集合框架
集合框架可以理解为一个容器,该容器主要指映射(map)、集合(set)、数组(array)和列表(list)等抽象数据结构。
从本质上来说,Java集合框架的主要组成是用来操作对象的接口。不同接口描述不同的数据类型。
简单介绍:
Collection接口是最基本的接口,它定义了List和Set,List又定义了LinkLi
旗正4.0页面跳转传值问题
何必如此
java jsp
跳转和成功提示
a) 成功字段非空forward
成功字段非空forward,不会弹出成功字段,为jsp转发,页面能超链接传值,传输变量时需要拼接。接拼接方式list.jsp?test="+strweightUnit+"或list.jsp?test="+weightUnit+&qu
全网唯一:移动互联网服务器端开发课程
cocos2d-x小菜
web开发 移动开发 移动端开发 移动互联 程序员
移动互联网时代来了! App市场爆发式增长为Web开发程序员带来新一轮机遇,近两年新增创业者,几乎全部选择了移动互联网项目!传统互联网企业中超过98%的门户网站已经或者正在从单一的网站入口转向PC、手机、Pad、智能电视等多端全平台兼容体系。据统计,AppStore中超过85%的App项目都选择了PHP作为后端程
Log4J通用配置|注意问题 笔记
7454103
DAO apache tomcat log4j Web
关于日志的等级 那些去 百度就知道了!
这几天 要搭个新框架 配置了 日志 记下来 !做个备忘!
#这里定义能显示到的最低级别,若定义到INFO级别,则看不到DEBUG级别的信息了~!
log4j.rootLogger=INFO,allLog
# DAO层 log记录到dao.log 控制台 和 总日志文件
log4j.logger.DAO=INFO,dao,C
SQLServer TCP/IP 连接失败问题 ---SQL Server Configuration Manager
darkranger
sql c windows SQL Server XP
当你安装完之后,连接数据库的时候可能会发现你的TCP/IP 没有启动..
发现需要启动客户端协议 : TCP/IP
需要打开 SQL Server Configuration Manager...
却发现无法打开 SQL Server Configuration Manager..??
解决方法: C:\WINDOWS\system32目录搜索framedyn.
[置顶] 做有中国特色的程序员
aijuans
程序员
从出版业说起 网络作品排到靠前的,都不会太难看,一般人不爱看某部作品也是因为不喜欢这个类型,而此人也不会全不喜欢这些网络作品。究其原因,是因为网络作品都是让人先白看的,看的好了才出了头。而纸质作品就不一定了,排行榜靠前的,有好作品,也有垃圾。 许多大牛都是写了博客,后来出了书。这些书也都不次,可能有人让为不好,是因为技术书不像小说,小说在读故事,技术书是在学知识或温习知识,有些技术书读得可
document.domain 跨域问题
avords
document
document.domain用来得到当前网页的域名。比如在地址栏里输入:javascript:alert(document.domain); //www.315ta.com我们也可以给document.domain属性赋值,不过是有限制的,你只能赋成当前的域名或者基础域名。比如:javascript:alert(document.domain = "315ta.com");
关于管理软件的一些思考
houxinyou
管理
工作好多看年了,一直在做管理软件,不知道是我最开始做的时候产生了一些惯性的思维,还是现在接触的管理软件水平有所下降.换过好多年公司,越来越感觉现在的管理软件做的越来越乱.
在我看来,管理软件不论是以前的结构化编程,还是现在的面向对象编程,不管是CS模式,还是BS模式.模块的划分是很重要的.当然,模块的划分有很多种方式.我只是以我自己的划分方式来说一下.
做为管理软件,就像现在讲究MVC这
NoSQL数据库之Redis数据库管理(String类型和hash类型)
bijian1013
redis 数据库 NoSQL
一.Redis的数据类型
1.String类型及操作
String是最简单的类型,一个key对应一个value,string类型是二进制安全的。Redis的string可以包含任何数据,比如jpg图片或者序列化的对象。
Set方法:设置key对应的值为string类型的value
Tomcat 一些技巧
征客丶
java tomcat dos
以下操作都是在windows 环境下
一、Tomcat 启动时配置 JAVA_HOME
在 tomcat 安装目录,bin 文件夹下的 catalina.bat 或 setclasspath.bat 中添加
set JAVA_HOME=JAVA 安装目录
set JRE_HOME=JAVA 安装目录/jre
即可;
二、查看Tomcat 版本
在 tomcat 安装目
【Spark七十二】Spark的日志配置
bit1129
spark
在测试Spark Streaming时,大量的日志显示到控制台,影响了Spark Streaming程序代码的输出结果的查看(代码中通过println将输出打印到控制台上),可以通过修改Spark的日志配置的方式,不让Spark Streaming把它的日志显示在console
在Spark的conf目录下,把log4j.properties.template修改为log4j.p
Haskell版冒泡排序
bookjovi
冒泡排序 haskell
面试的时候问的比较多的算法题要么是binary search,要么是冒泡排序,真的不想用写C写冒泡排序了,贴上个Haskell版的,思维简单,代码简单,下次谁要是再要我用C写冒泡排序,直接上个haskell版的,让他自己去理解吧。
sort [] = []
sort [x] = [x]
sort (x:x1:xs)
| x>x1 = x1:so
java 路径 配置文件读取
bro_feng
java
这几天做一个项目,关于路径做如下笔记,有需要供参考。
取工程内的文件,一般都要用相对路径,这个自然不用多说。
在src统计目录建配置文件目录res,在res中放入配置文件。
读取文件使用方式:
1. MyTest.class.getResourceAsStream("/res/xx.properties")
2. properties.load(MyTest.
读《研磨设计模式》-代码笔记-简单工厂模式
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
package design.pattern;
/*
* 个人理解:简单工厂模式就是IOC;
* 客户端要用到某一对象,本来是由客户创建的,现在改成由工厂创建,客户直接取就好了
*/
interface IProduct {
SVN与JIRA的关联
chenyu19891124
SVN
SVN与JIRA的关联一直都没能装成功,今天凝聚心思花了一天时间整合好了。下面是自己整理的步骤:
一、搭建好SVN环境,尤其是要把SVN的服务注册成系统服务
二、装好JIRA,自己用是jira-4.3.4破解版
三、下载SVN与JIRA的插件并解压,然后拷贝插件包下lib包里的三个jar,放到Atlassian\JIRA 4.3.4\atlassian-jira\WEB-INF\lib下,再
JWFDv0.96 最新设计思路
comsci
数据结构 算法 工作 企业应用 公告
随着工作流技术的发展,工作流产品的应用范围也不断的在扩展,开始进入了像金融行业(我已经看到国有四大商业银行的工作流产品招标公告了),实时生产控制和其它比较重要的工程领域,而
vi 保存复制内容格式粘贴
daizj
vi 粘贴 复制 保存原格式 不变形
vi是linux中非常好用的文本编辑工具,功能强大无比,但对于复制带有缩进格式的内容时,粘贴的时候内容错位很严重,不会按照复制时的格式排版,vi能不能在粘贴时,按复制进的格式进行粘贴呢? 答案是肯定的,vi有一个很强大的命令可以实现此功能 。
在命令模式输入:set paste,则进入paste模式,这样再进行粘贴时
shell脚本运行时报错误:/bin/bash^M: bad interpreter 的解决办法
dongwei_6688
shell脚本
出现原因:windows上写的脚本,直接拷贝到linux系统上运行由于格式不兼容导致
解决办法:
1. 比如文件名为myshell.sh,vim myshell.sh
2. 执行vim中的命令 : set ff?查看文件格式,如果显示fileformat=dos,证明文件格式有问题
3. 执行vim中的命令 :set fileformat=unix 将文件格式改过来就可以了,然后:w
高一上学期难记忆单词
dcj3sjt126com
word english
honest 诚实的;正直的
argue 争论
classical 古典的
hammer 锤子
share 分享;共有
sorrow 悲哀;悲痛
adventure 冒险
error 错误;差错
closet 壁橱;储藏室
pronounce 发音;宣告
repeat 重做;重复
majority 大多数;大半
native 本国的,本地的,本国
hibernate查询返回DTO对象,DTO封装了多个pojo对象的属性
frankco
POJO hibernate查询 DTO
DTO-数据传输对象;pojo-最纯粹的java对象与数据库中的表一一对应。
简单讲:DTO起到业务数据的传递作用,pojo则与持久层数据库打交道。
有时候我们需要查询返回DTO对象,因为DTO
Partition List
hcx2013
partition
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of th
Spring MVC测试框架详解——客户端测试
jinnianshilongnian
上一篇《Spring MVC测试框架详解——服务端测试》已经介绍了服务端测试,接下来再看看如果测试Rest客户端,对于客户端测试以前经常使用的方法是启动一个内嵌的jetty/tomcat容器,然后发送真实的请求到相应的控制器;这种方式的缺点就是速度慢;自Spring 3.2开始提供了对RestTemplate的模拟服务器测试方式,也就是说使用RestTemplate测试时无须启动服务器,而是模拟一
关于推荐个人观点
liyonghui160com
推荐系统 关于推荐个人观点
回想起来,我也做推荐了3年多了,最近公司做了调整招聘了很多算法工程师,以为需要多么高大上的算法才能搭建起来的,从实践中走过来,我只想说【不是这样的】
第一次接触推荐系统是在四年前入职的时候,那时候,机器学习和大数据都是没有的概念,什么大数据处理开源软件根本不存在,我们用多台计算机web程序记录用户行为,用.net的w
不间断旋转的动画
pangyulei
动画
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M
自定义annotation
sha1064616837
java enum annotation reflect
对象有的属性在页面上可编辑,有的属性在页面只可读,以前都是我们在页面上写死的,时间一久有时候会混乱,此处通过自定义annotation在类属性中定义。越来越发现Java的Annotation真心很强大,可以帮我们省去很多代码,让代码看上去简洁。
下面这个例子 主要用到了
1.自定义annotation:@interface,以及几个配合着自定义注解使用的几个注解
2.简单的反射
3.枚举
Spring 源码
up2pu
spring
1.Spring源代码
https://github.com/SpringSource/spring-framework/branches/3.2.x
注:兼容svn检出
2.运行脚本
import-into-eclipse.bat
注:需要设置JAVA_HOME为jdk 1.7
build.gradle
compileJava {
sourceCompatibilit
利用word分词来计算文本相似度
yangshangchuan
word word分词 文本相似度 余弦相似度 简单共有词
word分词提供了多种文本相似度计算方式:
方式一:余弦相似度,通过计算两个向量的夹角余弦值来评估他们的相似度
实现类:org.apdplat.word.analysis.CosineTextSimilarity
用法如下:
String text1 = "我爱购物";
String text2 = "我爱读书";
String text3 =