资源描述
标题,第一级,第二级,第三级,第四级,第五级,2020/1/27,浏览器工作原理浅析,TID Ghostzhang,本,PPT,只是对内容的一个整理,浏览器主要组件,用户界面,浏览器引擎,渲染引擎,网络,UI,后端,JS,解释器,数据存储,渲染引擎,Gecko,webkit,渲染引擎基本流程,构,建,dom,树,-,构建,render,树,-,布局,render,树,-,绘制,render,树,webkit,渲染引擎,主,流程,webkit,使用,render,树,这,个名词来命名由渲染对象组成的树,。,元,素的定位称,为,布局,。,利用,dom,节点及样式信息去构建,render,树的过程,为,attachment,Gecko,渲,染引擎主流程,Gecko,称可见的格式化元素组成的树为,frame,树,,每个元素都是一个,frame,。,元,素的定位称,为,回,流,。,Gecko,在,html,和,dom,树之间附加了一层,这层称,为,内,容接收器,,相当制造,dom,元素的工厂。,解析,流程,浏览器引擎,解,析,解析一个文,档:即,将其转换为,具有一定意义,的结构,编码可以理解和使用的东西,。,解,析的结果通常是表达文档结构的节点树,称为,解析树,或,语法树,。,例如,解析“,2,3,1”,这个表达式,可能返回这样一棵树。,数学表达式树节点,解,析,解析可以分为两个子过,程,语,法分,析:,对语言应用语法规则。,词,法分,析:,将输入分解为符号,符号是语言的词汇表,基本有效单元的集合。,解析器,词法,分析,及语法,分析,原文件,词法,分,析,语,法,分,析,解,析,树,从源文档到解析树,解析器,-,文法,上下文无关文法,如果一个语言的文法是上下文无关的,则它可以用正则解析器来解析。对上下文无关文法的一个直观的定义是,该文法可以用,BNF,来完整的表达。,BNF,:,http,:/en.wikipedia.org/wiki/Context-free_grammar,从源,文档到,解析树,解析器类型,解析器类型分为两种:,自,顶向下解,析:查,看语法的最高层结构并试着匹配其中一个,;,自,底向上解,析:从,输入开始,逐步将其转换为语法规则,从底层规则开始直到匹配高层规则,。,Webkit,使用自底向上的解析器,,Gecko,使用自顶向下的解析,器,例,子:,解析“,2,3,1”,这个表达式,词汇表:包括整数、加号及减号。,语法:,该语言的语法基本单元包括表达式、,term,及操作符,该语言可以包括多个表达式,一个表达式定义为两个,term,通过一个操作符连接,操作符可以是加号或减号,term,可以是一个整数或一个表达式,例子:词,汇表及语法的定义,INTEGER,:,0,1,9,0,9,PLUS,:,MINUS,:,词汇表:包括整数、加号及减号。,expression:,term operation term,operation:=PLUS|MINUS,term:=INTEGER|expression,语法:,该语言的语法基本单元包括表达式、,term,及操作符,该语言可以包括多个表达式,一个表达式定义为两个,term,通过一个操作符连接,操作符可以是加号或减号,term,可以是一个整数或一个表达式,例子:解析过程,第,一个匹配规则的子字符串是“,2”,,根据规则,5,,它是一个,term,第,二个匹配的是“,2,3”,,它符合第,2,条规则,一个操作符连接两个,term,,,下一次匹配发生在输入的结束处,。,“,2,3,1”,是一个表达式,因为我们已经知道“,2,3”,是一个,term,,所以我们有了一个,term,紧跟着一个操作符及另一个,term,。,“,2,”将不会匹配任何规则,因此是一个无效输入。,HTML,解析,非上下文无关文法,HTML,解析,HTML,文法定,义,HTML,DTD,DTD,(,Document Type Definition,文档类型定义),这一格式是用于定义,SGML,家族的语言,包括了对所有允许元素及它们的属性和层次关系的定义,。,DTD,定义了,HTML,的解析语法,HTML,解析树,DOM,树,HTML,解析器输,出的树,也就是解析树,是由,DOM,元素及属性节点组成的,。,DOM,是文档对象模型的缩写,它是,html,文档的对象表示,作为,html,元素的外部接口供,js,等调用。,www.w3.org/DOM/DOMTR,例子:,DOM,树,Hello DOM,这里所谓的树包含了,DOM,节点是说树是,由,实,现了,DOM,接口的元,素,构,建而成的,浏览器使用已被浏览器内部使用的其他属性的具体实现。,解析算法,hmtl,不能被一般的自顶向下或自底向上的解析器所解析。,原因是:,1.,这门语言本身的宽容特性,2.,浏览器对一些常见的非法,html,有容错机制,3.,解析过程是往复的,通常源码不会在解析过程中发生改变,但在,html,中,脚本标签包含的“,document.write”,可能添加标签,这说明在解析过程中实际上修改了输入,不能使用正则解析技术,浏览器为,html,定制了专属的解析器,。,Html5,规范中描述了这个解析算法,算法包括两个阶段,符号化及构建树,。,符号化,符号化是词法分析的过程,将输入解析为符号,,html,的符号包括开始标签、结束标签、属性名及属性值,。,符号识别器识别出符号后,将其传递给树构建器,并读取下一个字符,以识别下一个符号,这样直到处理完所有输入。,符号化:词法分析,Hello world,算法输出,html,符号,该算法用状态机表示。,构,建树,Hello world,构建树这一阶段的输入是符号识别阶段生成的符号序列。,解析结束时的处理,在这个阶段,浏览器将文档标记为可交互的,并开始解析处于延时模式中的脚本,这些脚本在文档解析后执行。,文档状态将被设置为完成,同时触发一个,load,事件,。,Html5,规范中有符号化及构建树的完整算法,(www.w3.org/TR/html5/syntax.html#html-parser),。,浏览器容错,浏览器都具有错误处理的能力,但是,另人惊讶的是,这并不是,html,最新规范的内容,就像书签及前进后退按钮一样,它只是浏览器长期发展的结果,。,解析器将符号化的输入解析为文档并创建文档,但不幸的是,我们必须处理很多没有很好格式化的,html,文档,至少要小心下面几种错误情况,。,标签未关闭,标,签嵌套错误,标,签,错,误,遗,漏标签,太深的标签继,承,,最,多只允许,20,个相同类型的标签嵌,套,。,CSS,解析,上下文无关文法,CSS,解析,-,词法,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 nmstartnmchar*,CSS,解析,-,语法,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*),;,“,ident”,是识别器的缩写,相当于一个,class,名,“,name”,是一个元素,id,(用“”引用)。,CSS,解析器,Webkit,使用自底向上的解析器,,Gecko,使用自顶向下的解析器,它们都是将每个,css,文件解析为样式表对象,每个对象包含,css,规则,,css,规则对象包含选择器和声明对象,以及其他一些符合,css,语法的对象。,脚本解析,javascript,脚本,web,的模式是同步的,开发者希望解析到一个,script,标签时立即解析执行脚本,并阻塞文档的解析直到脚本执行完,。,如,果脚本是外引的,则网络必须先请求到这个资源,这个过程也是同步的,会阻塞文档的解析直到资源被请求到,。这,个模式保持了很多年,并且在,html4,及,html5,中都特别指定了,。,开,发者可以将脚本标识为,defer,,以使其不阻塞文档解析,并在文档解析结束后执行。,Html5,增加了标记脚本为异步的选项,以使脚本的解析执行使用另一个线程。,预解析,Webkit,和,Firefox,都做了这个优化,当执行脚本时,另一个线程解析剩下的文档,并加载后面需要通过网络加载的资源,。,这,种方式可以使资源并行加载从而使整体速度更快,。,需,要注意的是,预解析并不改变,Dom,树,它将这个工作留给主解析过程,自己只解析外部资源的引用,比如外部脚本、样式表及图片。,样式表,样式表采用另一种不同的模式,。,理,论上,既然样式表不改变,Dom,树,也就没有必要停下文档的解析等待它们,然而,存在一个问题,脚本可能在文档的解析过程中请求样式信息,如果样式还没有加载和解析,脚本将得到错误的值,显然这将会导致很多问题,这看起来是个边缘情况,但确实很常见,。,Firefox,在存在样式表还在加载和解析时阻塞所有的脚本,而,chrome,只在当脚本试图访问某些可能被未加载的样式表所影响的特定的样式属性时才阻塞这些脚本。,渲染树的构,造,渲染引擎,渲染树,渲染树由,元素显示序列中的可见元素组成,,它是文档的可视化表示,构建这棵树是为了以正确的顺序绘制文档内容,。,Firefox,将渲染树中的元素称为,frames,,,webkit,则用,render,或渲染对象来描述这些元素。,一个渲染对,象知道怎,么布局及绘制自己及它的,children,。,每个渲染对象用一个和该节点的,css,盒模型相对应的,矩形区域,来表示,正如,css2,所描述的那样,它包含诸如宽、高和位置之类的几何信息。盒模型的类型受该节点相关的,display,样式属性的影,响。,元素的类型也需要考虑,例如,表单控件和表格带有特殊的框架。,渲染树和,DOM,树,的关,系,渲染对象和,DOM,元,素相对应,但这种对应关系,不是一对一,的,,不可见的,Dom,元素不会被插入渲染树,,例如,head,元素。另外,,display,属性为,none,的元素也不会在渲染树中出现,(,visibility,属性为,hidden,的元素将出现在渲染树中,)。,还有一些,Dom,元素对应几个可见对象,它们一般是一些具有复杂结构的元素,无法用一个矩形来描述,。,例如,,select,元素有三个渲染对象,一个显示区域、一个下拉列表及一个按钮,。,当文本因为宽度不够而折行时,,新行将作为额外的渲染元素被添加,。,根据,css,规范,一个行内元素只能仅包含行内元素或仅包含块状元素,在,存在混合内容时,将会创建匿名的块状渲染对象包裹住行内元素。,渲染树和,DOM,树的关系,一些渲染对象和所对应的,Dom,节点不在树上相同的位置,例如,浮动和绝对定位的元素在文本流之外,在两棵树上的位置不同,渲染树上标识出真实的结构,并用一个占位结构标识出它们原来的位置。,样式计,算,创建渲染树需要计算出每个渲染对象的可视属性,这可以通过计算每个元素的样式属性得到,。,样式包括各种来源的样式表,行内样式元素及,html,中的可视化属性(例如,bgcolor,),可视化属性转化为,css,样式属性。,样式表来源于浏览器默认样式表,及页面作者和用户提供的样式,表,有,些样式是浏览器用户提供的(浏览器允许用户定义喜欢的样式,例如,在,Firefox,中,可以通过在,Firefox Profile,目录下放置样式表实现,)。,计算样式的一些困难,计,算样式的一些困难,样式数据是非常大的结构,保存大量的样式属性会带来内存问,题,元素,查,找匹配的规,则的优化,应用规则涉及非常复杂的级,联,例子:复杂的选择符,div div div div,cont,div,div,div,?,Gecko,-,规则树、上下文树,Gecko-,规,则,树、上下文树,Gecko,用,两个树用来简化样式计算规则树和样式上下文,树,webkit,也有样式对象,但它们并没有存储在类似样式上下文树这样的树中,只是由,Dom,节点指向其相关的样式。,例子:使用规则树计算样式上下文,this is a,big error,this is also a,very big error,error,another error,1.div margin:5px;color:black,2.err color:red,3.big margin-top:3px,4.div span margin-bottom:4px,5.#div1 color:blue,6.#div2 color:green,简化下问题,我们只填充两个结构,color,和,margin,,,color,结构只包含一个成员颜色,,margin,结构包含四边。,例,子:规则树(指向规则),this is a,big error,this is also a,very big error,error,another error,1.div margin:5px;color:black,2.err color:red,3.big margin-top:3px,4.div span margin-bottom:4px,5.#div1 color:blue,6.#div2 color:green,例,子:上下文树(指向规则节点),this is a,big error,this is also a,very big error,error,another error,例子:,another error,1.div margin:5px;color:black,2.err color:red,3.big margin-top:3px,4.div span margin-bottom:4px,5.#div1 color:blue,6.#div2 color:green,例子:,another error,规则树路径:,1,、,2,、,6,计算规则,缓存结果:,margin-top:5px;,margin-bottom:5px;,margin-left:5px;,margin-right:5px;,color:#00FF00;,创建节点,关联上下文树,结构化,样式上下文按结构划分,,一,个结构中的所有特性不是继承的就是非继承,的。,对,继承的特性,除非元素自身有定义,否则就从它的,parent,继承,。,非,继承的特性(称为,reset,特性)如果没有定义,则使用默认的值。,例子:,another error,margin-top:5px;,margin-bottom:5px;,margin-left:5px;,margin-right:5px;,color:#000000,;,color,:#FF0000;,color,:#00FF00;,例子:,another error,例子:,another error,margin-top:5px;,margin-bottom:5px;,margin-left:5px;,margin-right:5px;,color:#00FF00;,样式规则的来源,外部样式或标签内,style,属性的,CSS,规则,行内,样,式属性,html,可视化属性(映射为相应的样式规则),通过映射提高匹配速度,样式规则可能很狡猾,为了解决这个问题,可以先对规则进行处理,以使其更容易被访问。,解析完样式表之后,规则会根据选择符添加一些,hash,映射,映射可以是根据,id,、,class,、标签名或是任何不属于这些分类的综合映射,。,如,果选择符为,id,,规则将被添加到,id,映射,,,如,果是,class,,则被添加到,class,映射,等等,。,这个处理是匹配规则更容易,不需要查看每个声明,我们能从映射中找到一个元素的相关规则,这个优化使在进行规则匹配时减少了,95,的工作量。,例子:映射,class,映射,id,映射,标签映射,1.div margin:5px;color:black,2.err color:red,3.big margin-top:3px,4.div span margin-bottom:4px,5.#div1 color:blue,6.#div2 color:green,例子:映射,p.error color:red,#,messagediv,height:50px,div margin:5px,an error occurred,this is a message,例子:映射,p.error color:red,#,messagediv,height:50px,div margin:5px,an error occurred,this is a message,HTML:A,BODY:A,P,DIV,例子:映射,p.error color:red,#messageDiv height:50px,div margin:5px,class,映射,id,映射,标签映射,例子:映射,p.error color:red,class,映射,id,映射,标签映射,例子:映射,p.error color:red,class,映射,标签映射,key,p,.error,例子:映射,A:null,B:null,C:1,HTML:A,BODY:A,P:,C,DIV,P,.error,例子:映射,A:null,B:null,C:1,D:3,E:2,HTML:A,BODY:A,P:C,DIV:E,webkit-,共,享样式数据,Webkit-,共,享样式数据,webkit,节点引用样式对象(渲染样式),某些情况下,这些对象可以被节点间共享,这些节点需要是兄弟或是表兄弟节点,并且:,这些元素必须处于相同的鼠标状态(比如不能一个处于,hover,,而另一个不是),不能有元素具有,id,标签名必须匹配,class,属性必须匹配,对应的属性必须相同,链接状态必须匹配,焦点状态必须匹配,不能有元素被属性选择器影响,元素不能有行内样式属性,不能有生效的兄弟选择器,,webcore,在任何兄弟选择器相遇时只是简单的抛出一个全局转换,并且在它们显示时使整个文档的样式共享失效,这些包括选择器和类似,:first-child,和,:last-child,这样的选择器。,遍,历,匹配,Webkit,中,并没有规则树,匹配的声明会被遍历四,次,先,是应用非,important,的高优先级属性(之所以先应用这些属性,是因为其他的依赖于它们比如,display,),,其,次是高优先级,important,的,,,接,着是一般优先级非,important,的,,,最,后是一般优先级,important,的规则,。,这,样,出现多次的属性将被按照正确的,级联顺序,进行处理,最后一个生效。,样式表的级联顺序,一个样式属性的声明可能在几个样式表中出现,或是在一个样式表中出现多次,因此,应用规则的顺序至关重要,,这个顺序就是级联顺序。,根据,css2,的规范,级联顺序为(从低到高):,1.,浏览器声明,2.,用户声明,3.,作者的一般声明,4.,作者的,important,声明,5.,用户,important,声,明,Specifity,(权值),Css2,规范中定义的选择符,specifity,如下:,如,果声明来自,style,属性,而不是一个选择器的规则,则计,1,,否则计,0,(,a,),计,算选择器中,id,属性的数量(,b,),计,算选择器中,class,及伪类的数量(,c,),计,算选择器中元素名及伪元素的数量(,d,),连接,a,b,c,d,四个数量(用一个大基数的计算系统)将得到,specifity,。这里使用的,基数由分类中最高的基数定义,。,规则排序,规则匹配后,需要根据级联顺序对规则进行排序,,webkit,先将小列表用冒泡排序,再将它们合并为一个大列,表。,逐步处理,webkit,使用一个标志位标识所有顶层样式表都已加载,如果在,attch,时样式没有完全加载,则放置占位符,并在文档中标记,一旦样式表完成加载就重新进行计算。,布局,layout/reflow,布局,当渲染对象被创建并添加到树中,它们并没有位置和大小,计算这些值的过程称为,layout,或,reflow,。,Html,使用基于流的布局模,型。,流中靠后的元素并不会影响前面元素的几何特性,所以布局可以在文档中从右向左、自上而下的进行。也存在一些例外,比如,html tables,。,坐标系统相对于根,frame,,使用,top,和,left,坐标,。,根渲染对象的位置是,0,0,,它的大小是,viewport,浏览器窗口的可见部分。,布局是一个递归的过程,由根渲染对象开始,它对应,html,文档元素,布局继续递归的通过一些或所有的,frame,层级,为每个需要几何信息的渲染对象进行计算。,Dirty bit,系统,为了不因为每个小变化都全部重新布局,浏览器使用一个,dirty bit,系统,一个渲染对象发生了变化或是被添加了,就标记它及它的,children,为,dirty,。,存,在两个标,识,dirty,:需,要,layout,。,children,are,dirty,:即,使这个渲染对象可能没问题,但它至少有一个,child,需要,layout,。,全局和增量,layout,当,layout,在整棵渲染树触发时,称为全局,layout,,这可能在下面这些情况下发生:,1.,一个全局的样式改变影响所有的渲染对象,比如字号的改变,2.,窗口,resize,layout,也可以是增量的,这样只有标志为,dirty,的渲染对象会重新布局(也将导致一些额外的布局)。增量,layout,会在渲染对象,dirty,时异步触发,例如,当网络接收到新的内容并添加到,Dom,树后,新的渲染对象会添加到渲染树中。,异步和同步,layout,增量,layout,的过程是异步,的,Firefox,为增量,layout,生成了,reflow,队列,以及一个调度执行这些批处理命令,。,Webkit,也有一个计时器用来执行增量,layout,遍历树,为,dirty,状态的渲染对象重新布局。,另外,当脚本请求样式信息时,例如“,offsetHeight”,,会同步的触发增量布局。,全局的,layout,一般都是同步触发。,有些时候,,layout,会被作为一个初始,layout,之后的回调,比如滑动条的滑动。,优化,当一个,layout,因为,resize,或是渲染位置改变(并不是大小改变)而触发时,渲染对象的大小将会从缓存中读取,而不会重新计算。,一般情况下,如果只有子树发生改变,则,layout,并不从根开始。这种情况发生在,变化发生在元素自身并且不影响它周围元素,例如,将文本插入文本域(否则,每次击键都将触发从根开始的重排,)。,layout,过程,layout,过程,parent,渲染对象决定它的宽度,parent,渲染对象读取,chilidren,,并:,放,置,child,渲染对象(设置它的,x,和,y,),在,需要时(它们当前为,dirty,或是处于全局,layout,或者其他原因)调用,child,渲染对象的,layout,,这将计算,child,的高,度,parent,渲染对象使用,child,渲染对象的累积高度,以及,margin,和,padding,的高度来设置自己的高度这将被,parent,渲染对象的,parent,使用,将,dirty,标识设置为,false,Firefox,使用一个“,state”,对象(,nsHTMLReflowState,)做为参数去布局(,firefox,称为,reflow,),,state,包含,parent,的宽度及其他内容。,Firefox,布局的输出是一个“,metrics”,对象(,nsHTMLReflowMetrics,)。它包括渲染对象计算出的高度,。,宽度计算,webkit,中宽度的计算过程是(,RenderBox,类的,calcWidth,方法):,容,器的宽度是容器的可用宽度和,0,中的最大值,这里的可用宽度为:,contentWidth=clientWidth()-paddingLeft()-paddingRight,(),clientWidth,和,clientHeight,代表一个对象内部的不包括,border,和滑动条的大小,元,素的宽度指样式属性,width,的值,它可以通过计算容器的百分比得到一个绝对值,加,上水平方向上的,border,和,padding,到这里是最佳宽度的计算过程,现在计算宽度的最大值和最小,值,如,果最佳宽度大于最大宽度则使用最大宽,度,如,果小于最小宽度则使用最小宽度,。,最,后缓存这个值,当需要,layout,但宽度未改变时使用。,Line breaking,当一个渲染对象在布局过程中需要折行时,则暂停并告诉它的,parent,它需要折行,,parent,将创建额外的渲染对象并调用它们的,layout,。,绘制,显示内容,全局和增量,和布局一样,绘制也可以是全局的绘制完整的树或增量的,。,在,增量的绘制过程中,一些渲染对象以不影响整棵树的方式改变,改变的渲染对象使其在屏幕上的矩形区域失效,这将导致操作系统将其看作,dirty,区域,并产生一个,paint,事件,操作系统很巧妙的处理这个过程,并将多个区域合并为一个。,Chrome,中,这个过程更复杂些,因为渲染对象在不同的进程中,而不是在主进程中。,Chrome,在一定程度上模拟操作系统的行为,表现为监听事件并派发消息给渲染根,在树中查找到相关的渲染对象,重绘这个对象(往往还包括它的,children,)。,绘制顺序,这个就是元素压入堆栈的顺序,这个顺序影响着绘制,堆栈从后向前进行绘制。,一个块渲染对象的堆栈顺序是:,背,景色,背,景图,border,children,outline,css2,定义了绘制过程的顺,序:,http,:/www.w3.org/TR/CSS21/zindex.html,总结,工作中需要注意的内容,代码,不规范的,HTML,结构会降低页面解析效率(,HTML,),HTML,的节点、层级越少页面解析效率越高(,HTML,),通配选择符对性能的影响几乎可以忽略(,CSS,),包含选择符的层级过多会导致降低样式解析效率(,CSS,),不显示的对象不会被渲染(,CSS,),动态变化,浏览器总是试着以最小的动作响应一个变,化,一,个元素颜色的变化将只导致该元素的重,绘,元,素位置的变化,将导致,元素的布局和重,绘,添,加一个,Dom,节点,也会大致这个元素的布局和重,绘,一,些主要的变化,比如增加,html,元素的字号,将会导致缓存失效,从而引起整数的布局和重绘。,Thanks,no Q&A,CSSForest.org,
展开阅读全文