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,浏览器工作原理)
“傻瓜”学计量——主成分分析法PCA(原理+实操)
nn坚持学stata+matlab
计量 算法 机器学习 人工智能 学习 笔记 学习方法 经验分享
提纲:1.PCA原理2.视频推荐:PCA原理spass操作stata操作+matlab实操1.背景在一些领域中,需要对大量数据进行观测。但是可能会带来变量之间具有相关性、分别对每个指标分析带来的偏误等问题。因此,要寻找一个合理的方法,在减少需要分析的直白的同时,尽量减少原指标包含的信息缺失。通常做法是对有关联性的变量进行合并,这样就可以用较少的综合指标分别代表存在于各个变量中的各类信息。常用的方法
网络安全常见十大漏洞总结(原理、危害、防御)
程序媛西米
网络安全 数据库 oracle 网络 web安全 计算机 网络安全 安全
一、弱口令【文末福利】产生原因与个人习惯和安全意识相关,为了避免忘记密码,使用一个非常容易记住的密码,或者是直接采用系统的默认密码等。危害通过弱口令,攻击者可以进入后台修改资料,进入金融系统盗取钱财,进入OA系统可以获取企业内部资料,进入监控系统可以进行实时监控等等。防御设置密码通常遵循以下原则:(1)不使用空口令或系统缺省的口令,为典型的弱口令;(2)口令长度不小于8个字符;(3)口令不应该为连
ADC(模数转换器)与DAC(数模转换器)详解:从基础到应用示例
楼台的春风
嵌入式开发 STM32 嵌入式 c语言 mcu 自动驾驶 嵌入式硬件 stm32 物联网
ADC(模数转换器)与DAC(数模转换器)详解:从基础到应用示例目录ADC(模数转换器)与DAC(数模转换器)详解:从基础到应用示例引言一、ADC(模数转换器)1.ADC的基本概念2.ADC的工作原理3.ADC的主要类型4.ADC的技术指标5.ADC的应用场景6.ADC在嵌入式系统中的使用案例二、DAC(数模转换器)1.DAC的基本概念2.DAC的工作原理3.DAC的主要类型4.DAC的技术指标5
MySQL 查询缓存技术深度解析
Minxinbb
数据库 mysql 数据库 dba
在现代数据库管理系统中,查询性能优化是提升应用响应速度和用户体验的关键环节。MySQL作为一款广泛使用的开源关系型数据库,提供了查询缓存功能,用于缓存查询结果,从而在后续相同的查询请求时能够快速返回结果,减少数据库的负载和查询时间。本文将深入探讨MySQL查询缓存技术的原理、配置、使用方法以及优化策略。一、查询缓存的基本原理(一)缓存机制概述MySQL查询缓存的核心思想是将查询语句和其对应的查询结
docker部署kafka(单节点) + Springboot集成kafka
wsdhla
docker kafka spring boot zookeeper
环境:操作系统:win10Docker:DockerDesktop4.21.1(114176)、DockerEnginev24.0.2SpringBoot:2.7.15步骤1:创建网络:dockernetworkcreate--subnet=172.18.0.0/16net-kafka步骤2:安装zk镜像dockerpullzookeeper:latestdockerrun-d--restarta
内存缓冲区溢出原理和预防措施
Utopia.️
网络 安全 服务器
内存缓冲区溢出(BufferOverflow)是一种常见的安全漏洞,发生在程序试图向内存缓冲区写入超出其容量的数据时。这种溢出可以覆盖相邻的内存区域,可能导致程序崩溃或被攻击者利用来执行恶意代码。内存缓冲区溢出的原理缓冲区的定义:缓冲区是用于临时存储数据的内存区域。例如,字符数组或数据结构。溢出发生:当程序将数据写入缓冲区时,如果写入的数据超出了缓冲区的边界,超出的数据会覆盖相邻的内存区域。这可能
数据包结构
Utopia.️
网络 开发语言
据包(数据包)结构是网络通信中的基本组成部分。它定义了在网络上传输数据时的组织方式和格式。了解数据包的结构有助于理解网络通信的工作原理,排查网络问题以及优化网络性能。以下是对数据包结构的详细解释:数据包的基本组成数据包通常由以下几个主要部分组成:头部(Header):定义:头部包含了用于路由和控制的数据包的元数据。这部分信息帮助网络设备(如路由器和交换机)正确地处理和转发数据包。内容:源地址和目的
cocos creator从零开发简单框架(12)-代码生成单色Sprite
cocos
在写Panel前,先写个方法生成单色Sprite,这样当碰到需要单色Sprite的时候不需要在编辑器拖拽和代码动态加载资源。编辑framework/scripts/AppUtil.ts,添加newSpriteNode方法。//生成默认白色100x100大小Sprite(单色)节点publicstaticnewSpriteNode(name:string='newSpriteNode'):cc.No
cocos creator从零开发简单框架(14)-Panel遮罩
cocos
遮罩相关属性编辑framework/scripts/view/PanelMgr.ts,增加遮罩相关成员变量及初始化方法。//所有面板privatestatic_panels:Map=newMap()privatestatic_maskName='_mask'privatestatic_maskPrefab:cc.Nodepublicstaticinit(){this._panels.clear()
动态规划之背包问题全解
学会了,不,学废了
动态规划
概述———动态规划提出人:理查德·贝尔曼本质:一张表格处理方法内容:把原问题分解为若干子问题,自底向上先求解最小子问题,把结果储存在表格中,求解大的子问题时直接从表格中查询小的子问题的解,以避免重复计算,从而提高效率。一、动态规划求解原理适用范围:问题需要具备3个性质———最优子结构、子问题重叠、无后效性。最优子结构指问题最优解包含其子问题的最优解,是使用动态规划的基本条件。三要素:状态、阶段、决
《揭秘AI语音助手:从“听”到“说”的智能之旅》
人工智能深度学习
在当今数字化时代,AI语音助手已成为我们生活和工作中的得力伙伴。无论是苹果的Siri、亚马逊的Alexa,还是国内的小爱同学、小度等,它们能轻松执行指令,如查询天气、播放音乐,甚至陪我们聊天解闷。但你是否想过,这些语音助手是如何听懂我们的话语,又如何给出恰当回应的呢?今天,就让我们深入探索AI语音助手背后的技术原理。自动语音识别(ASR):让机器“听懂”人类语言自动语音识别(AutomaticSp
数据挖掘十大经典算法详解(附原理解析与代码示例)
IT程序媛-桃子
华为认证 数据挖掘 算法 经验分享 华为
1.PageRank(链接分析)应用场景:搜索引擎排名、社交网络分析核心原理PageRank通过网页之间的链接关系计算网页的重要性,影响力大的网页排名更高。网页影响力=所有入链页面的加权影响力之和阻尼因子D(通常设为0.85)用于模拟用户随机访问网页的行为代码示例importnetworkxasnxG=nx.DiGraph()G.add_edges_from([("A","B"),("A","C"
EasyX安装及使用
于冬恋
java 开发语言
安装链接:EasyXGraphicsLibraryforC++安装完成包含头文件graphics.h即可使用RGB合成颜色(红色部分,绿色部分,蓝色部分)每种颜色的值都是(0~255)坐标默认的原点在窗口的左上角,x轴向右为正,y轴向下为正,度量单位是像素点。设备:简单来说就是绘图表面(在EasyX中,设备分为两种,一种是默认的绘图窗口,一种是IMAGE对象。通过SetWorkinglmage()
网络协议、网络安全架构、网络安全标准
Utopia.️
网络协议 web安全 架构
1.网络协议网络协议是计算机网络中设备之间通信的规则集。熟悉常见的网络协议及其工作原理是确保网络安全的基础。常见协议:TCP/IP协议:这是网络通信的基础协议,确保数据从源端传输到目标端,支持多种传输方式(TCP可靠传输,UDP快速但不可靠)。HTTP/HTTPS:HTTP用于浏览器与服务器之间的通信,HTTPS则是在HTTP上添加了SSL/TLS加密层,用于确保数据传输的安全性。DNS协议:用于
JavaScript 闭包与作用域的深度解析
小钟H呀
JS知识手册 javascript 开发语言 ecmascript
引言在JavaScript世界里,闭包和作用域是两个核心概念,理解它们对于编写高效、可维护的代码至关重要。本文将深入探讨JavaScript闭包与作用域的原理、应用及注意事项。一、作用域的概念(一)什么是作用域作用域是指变量和函数的可访问范围。在JavaScript中,主要有全局作用域和局部作用域。全局作用域:在代码的任何地方都可以访问到的变量和函数,通常在脚本的最外层或通过全局对象(如windo
在瑞芯微RK3588平台上使用RKNN部署YOLOv8Pose模型的C++实战指南
机 _ 长
YOLO系列模型有效涨点改进 深度学习落地实战 YOLO c++ 开发语言
在人工智能和计算机视觉领域,人体姿态估计是一项极具挑战性的任务,它对于理解人类行为、增强人机交互等方面具有重要意义。YOLOv8Pose作为YOLO系列中的新成员,以其高效和准确性在人体姿态估计任务中脱颖而出。本文将详细介绍如何在瑞芯微RK3588平台上,使用RKNN(RockchipNeuralNetworkToolkit)框架部署YOLOv8Pose模型,并进行C++代码的编译和运行。注本文全
DeepSeek-R1 技术全景解析:从原理到实践的“炼金术配方” ——附多阶段训练流程图与核心误区澄清...
雪停时偶遇一叶春
流程图
合集-人工智能(5)1.如何改进AI模型在特定环境中的知识检索2024-09-242.深度学习与统计学中的时间序列预测2024-10-033.《使用coze搭建一个会搜索、写ppt、思维导图的Agent》2024-10-294.深入浅出:Agent如何调用工具——从OpenAIFunctionCall到CrewAI框架01-145.DeepSeek-R1技术全景解析:从原理到实践的“炼金术配方”—
分布式数据库解析
qcidyu
文章归档 数据分片 高可用架构 云数据库 共识算法 全球一致性 分布式事务 CAP定理
title:分布式数据库解析date:2025/2/20updated:2025/2/20author:cmdragonexcerpt:通过金融交易、社交平台、物联网等9大真实场景,结合GoogleSpanner跨洲事务、DynamoDB毫秒级扩展等38个生产级案例,揭示分布式数据库的核心原理与工程实践。内容涵盖CAP定理的动态权衡策略、Paxos/Raft协议的工程实现差异、TrueTime时钟
java竞赛优化输入输出效率
px不是xp
蓝桥准备 java 开发语言
在编程竞赛中,输入输出效率至关重要。Java的`Scanner`和`System.out.println`虽然简单,但在处理大规模数据时会严重拖慢速度。以下是**竞赛专用输入输出模板**及其原理详解,助你轻松应对高频I/O场景。---###⚡竞赛级输入输出模板(Java)importjava.io.*;importjava.util.*;publicclassMain{ publicstatic
HarmonyOS进程通信及原理
拥有一颗学徒的心
HarmonyOS harmonyos 华为 鸿蒙 信息与通信 分布式
大家好,我是学徒小z,最近在研究鸿蒙中一些偏底层原理的内容,今天分析进程通信给大家,请用餐文章目录进程间通信1.通过公共事件(@ohos.commonEventManager)公共事件的底层原理2.IPCKit能力LiteIPC的归属与特点1.所属内核2.核心思想3.公共事件子系统鸿蒙内核小知识进程间通信1.通过公共事件(@ohos.commonEventManager)公共事件的底层原理公共事件
深入了解 CDN:概念、原理、过程、作用及工作场景
羊村懒哥
网络 网络 加速缓存
目录一、CDN的概念二、CDN的工作原理三、CDN的工作过程四、CDN的作用五、CDN可结合使用的技术六、CDN能够解决的网络问题七、CDN的工作场景在当今互联网飞速发展的时代,用户对于网页加载速度和内容获取的时效性要求越来越高。CDN(ContentDeliveryNetwork,⭐内容分发网络)应运而生,它在提升网络性能和用户体验方面发挥着关键作用。本文将详细介绍CDN的概念、工作原理、工作过
OpenLayers总结3
Super毛毛穗
WebGIS开发 OpenLayers GIS WebGIS
一、静态测距1.原理静态测距主要是针对地图上已有的矢量要素(如线要素),利用OpenLayers提供的几何计算函数来获取其长度。在实际操作中,先加载包含几何要素的GeoJSON数据到矢量图层,当鼠标指针移动到要素上时,获取该要素的几何信息,再调用getLength函数计算其长度。2.代码实现步骤及注释//引入必要的模块importVectorLayerfrom"ol/layer/Vector.js
在线预览 Word 文档
你不讲 wood
word 开发语言 前端 vue.js javascript node.js docx-preview
引言随着互联网技术的发展,Web应用越来越复杂,用户对在线办公的需求也日益增加。在许多业务场景中,能够直接在浏览器中预览Word文档是一个非常实用的功能。这不仅可以提高用户体验,还能减少用户操作步骤,提升效率。实现原理1.后端服务假设后端服务已经提供了两个API接口:getFilesList:获取文件列表。previewFile:获取指定文件的内容。constexpress=require('ex
Transformer 模型架构
2401_89793006
热门话题 transformer 深度学习 人工智能
Transformer是一种模型架构(ModelArchitecture),而不是一个软件框架(Framework)。它的定位更接近于一种设计蓝图,类似于建筑中的结构设计方案。以下是详细解释:1.架构vs框架的区别概念定义示例模型架构定义神经网络的结构设计Transformer、CNN、RNN开发框架提供实现模型的工具和库PyTorch、TensorFlow2.Transformer作为架构的核心
MVCC(多版本并发控制)机制讲解
十五001
基础 oracle 数据库 mysql
MVCC(Multi-VersionConcurrencyControl,多版本并发控制)这是一个在数据库管理系统中非常重要的技术,尤其是在处理并发事务时。别担心,我会用简单易懂的方式来讲解,让你轻松掌握它的原理和作用。1.什么是MVCC?定义MVCC是一种数据库技术,用于通过保留数据的多个版本来提高并发性能,同时避免事务之间的冲突。简单来说,它允许数据库在读取和写入操作时,同时存在多个版本的数据
使用Python和OpenCV实现图像像素压缩与解压
东方佑
量子变法 python opencv 开发语言
在本文中,我们将探讨如何使用Python和OpenCV库来实现一种简单的图像像素压缩算法。我们将详细讨论代码的工作原理,并提供一个具体的示例来演示该过程。1.引言随着数字媒体的普及,图像处理成为了一个重要的领域。无论是为了减少存储空间还是加快网络传输速度,图像压缩技术都扮演着至关重要的角色。这里,我们提出了一种基于像素重复模式的简单压缩算法,它适用于具有大量连续相同像素值的图像。2.技术栈介绍2.
安装与部署openeuler 的HA
VX-IT BANG
服务器 网络 linux
实现原理LinuxHA(HighAvailability,高可用性)是指利用Linux操作系统构建的高可用集群解决方案,旨在确保关键业务服务在面临硬件故障、软件错误、网络中断等各种异常情况时,依然能够持续、稳定地运行,尽量减少服务中断时间,提高系统的可靠性和可用性。以下从几个方面详细介绍:关键组件和技术心跳监测(Heartbeat)这是LinuxHA系统中最基础也是最重要的组件之一。它通过在节点之
关于防火墙运维面试题
编织幻境的妖
运维 php 网络
一、防火墙基础概念类1.请详细阐述防火墙在网络安全体系中的具体作用及核心原理。以下是防火墙在网络安全体系中的具体作用及核心原理的详细阐述:防火墙在网络安全体系中的作用访问控制限制非法访问:防火墙可以根据预设的规则,允许或拒绝特定的网络流量通过。例如,企业内部网络可能只允许来自特定IP地址范围的员工访问敏感资源,而阻止其他未经授权的外部IP地址的访问,从而保护内部网络免受未经授权的访问和潜在的攻击。
改进YOLO系列 | YOLOv5/v7 引入 Dynamic Snake Convolution | 动态蛇形卷积
wei子
YOLO 目标跟踪 人工智能
改进YOLO系列:动态蛇形卷积(DynamicSnakeConvolution,DSC)简介YOLO系列目标检测算法以其速度和精度著称,但对于细长目标例如血管、道路等,其性能仍有提升空间。动态蛇形卷积(DSC)是YOLOv5/v7中引入的一种改进,旨在更好地处理细长目标。DSC原理DSC的核心思想是使用类似蛇形运动的卷积核来提取细长目标的特征。具体来说,DSC卷积核沿着一系列控制点移动,并根据每个
Java平台上的多线程与多核处理研究
向哆哆
Java入门到精通 java python 开发语言
Java平台上的多线程与多核处理研究在现代计算机架构中,多核处理器已成为主流。随着硬件性能的提升,如何有效利用多核处理器的计算能力成为开发者面临的重要问题之一。Java作为一种广泛使用的编程语言,提供了多线程编程的强大支持,使得开发者能够在多核环境下实现并行计算。本篇文章将深入探讨Java平台上的多线程与多核处理,探讨其工作原理、应用场景,并通过代码实例进行演示。1.多线程与多核处理的基本概念1.
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 =