精华内容
下载资源
问答
  • 浏览器工作原理3-解析与DOM树构建

    千次阅读 2017-03-30 19:59:16
    解析与DOM树构建 渲染树构建 布局 绘制 动态变化 渲染引擎的线程 CSS2可视模型 3. 解析与DOM树构建解析(Parsing-general)既然解析是渲染引擎中一个非常重要的过程,我们将稍微深入的研究它。首先简要介绍一下解析...

    浏览器工作原理3

    1. 介绍
    2. 渲染引擎
    3. 解析与DOM树构建
    4. 渲染树构建
    5. 布局
    6. 绘制
    7. 动态变化
    8. 渲染引擎的线程
    9. CSS2可视模型

    3. 解析与DOM树构建

    解析(Parsing-general)

    既然解析是渲染引擎中一个非常重要的过程,我们将稍微深入的研究它。首先简要介绍一下解析。

    解析一个文档即将其转换为具有一定意义的结构——编码可以理解和使用的东西。解析的结果通常是表达文档结构的节点树,称为解析树或语法树。

    例如,解析“2+3-1”这个表达式,可能返回这样一棵树。

    图5:数学表达式树节点

    文法(Grammars)

    解析基于文档依据的语法规则——文档的语言或格式。每种可被解析的格式必须具有由词汇及语法规则组成的特定的文法,称为上下文无关文法。人类语言不具有这一特性,因此不能被一般的解析技术所解析。

    解析器-词法分析器(Parser-Lexer combination)

    解析可以分为两个子过程——语法分析及词法分析

    词法分析就是将输入分解为符号,符号是语言的词汇表——基本有效单元的集合。对于人类语言来说,它相当于我们字典中出现的所有单词。

    语法分析指对语言应用语法规则。

    解析器一般将工作分配给两个组件——词法分析器(有时也叫分词器)负责将输入分解为合法的符号,解析器则根据语言的语法规则分析文档结构,从而构建解析树,词法分析器知道怎么跳过空白和换行之类的无关字符。

    图6:从源文档到解析树

    解析过程是迭代的,解析器从词法分析器处取到一个新的符号,并试着用这个符号匹配一条语法规则,如果匹配了一条规则,这个符号对应的节点将被添加到解析树上,然后解析器请求另一个符号。如果没有匹配到规则,解析器将在内部保存该符号,并从词法分析器取下一个符号,直到所有内部保存的符号能够匹配一项语法规则。如果最终没有找到匹配的规则,解析器将抛出一个异常,这意味着文档无效或是包含语法错误。

    转换(Translation)

    很多时候,解析树并不是最终结果。解析一般在转换中使用——将输入文档转换为另一种格式。编译就是个例子,编译器在将一段源码编译为机器码的时候,先将源码解析为解析树,然后将该树转换为一个机器码文档。

    图7:编译流程

    解析实例(Parsing example)

    图5中,我们从一个数学表达式构建了一个解析树,这里定义一个简单的数学语言来看下解析过程。

    词汇表:我们的语言包括整数、加号及减号。

    语法:

    1. 该语言的语法基本单元包括表达式、term及操作符
    2. 该语言可以包括多个表达式
    3. 一个表达式定义为两个term通过一个操作符连接
    4. 操作符可以是加号或减号
    5. term可以是一个整数或一个表达式

    现在来分析一下“2+3-1”这个输入

    第一个匹配规则的子字符串是“2”,根据规则5,它是一个term,第二个匹配的是“2+3”,它符合第2条规则——一个操作符连接两个term,下一次匹配发生在输入的结束处。“2+3-1”是一个表达式,因为我们已经知道“2+3”是一个term,所以我们有了一个term紧跟着一个操作符及另一个term。“2++”将不会匹配任何规则,因此是一个无效输入。

    词汇表及语法的定义

      
    词汇表通常利用正则表达式来定义。

    例如上面的语言可以定义为:

    INTEGER0|[19][09]*
    PLUS:+
    MINUS:-

    正如看到的,这里用正则表达式定义整数。

    语法通常用BNF格式定义,我们的语言可以定义为:

    expression := term operation term
    operation := PLUS | MINUS
    term := INTEGER | expression

    如果一个语言的文法是上下文无关的,则它可以用正则解析器来解析。对上下文无关文法的一个直观的定义是,该文法可以用BNF来完整的表达。可查看http://en.wikipedia.org/wiki/Context-free_grammar

    解析器类型(Types of parsers)

    有两种基本的解析器——自顶向下解析及自底向上解析。比较直观的解释是,自顶向下解析,查看语法的最高层结构并试着匹配其中一个;自底向上解析则从输入开始,逐步将其转换为语法规则,从底层规则开始直到匹配高层规则。

    来看一下这两种解析器如何解析上面的例子:

    自顶向下解析器从最高层规则开始——它先识别出“2+3“,将其视为一个表达式,然后识别出”2+3-1“为一个表达式(识别表达式的过程中匹配了其他规则,但出发点是最高层规则)。

    自底向上解析会扫描输入直到匹配了一条规则,然后用该规则取代匹配的输入,直到解析完所有输入。部分匹配的表达式被放置在解析堆栈中。

    Stack
    Input
    
    2 + 31
    term
    + 3 - 1
    term operation
    31
    expression
    - 1
    expression operation
    1
    expression

    自底向上解析器称为shift reduce解析器,因为输入向右移动(想象一个指针首先指向输入开始处,并向右移动),并逐渐简化为语法规则。

    自动化解析(Generating parsers automatically)

    解析器生成器这个工具可以自动生成解析器,只需要指定语言的文法——词汇表及语法规则,它就可以生成一个解析器。创建一个解析器需要对解析有深入的理解,而且手动的创建一个由较好性能的解析器并不容易,所以解析生成器很有用。Webkit使用两个知名的解析生成器——用于创建语法分析器的Flex及创建解析器的Bison(你可能接触过Lex和Yacc)。Flex的输入是一个包含了符号定义的正则表达式,Bison的输入是用BNF格式表示的语法规则。

    HTML解析器(HTML Parser)

    HTML解析器的工作是将html标识解析为解析树。

    HTML文法定义(The HTML grammar definition)

    W3C组织制定规范定义了HTML的词汇表和语法。

    非上下文无关文法(Not a context free grammar)

    正如在解析简介中提到的,上下文无关文法的语法可以用类似BNF的格式来定义。

    不幸的是,所有的传统解析方式都不适用于html(当然我提出它们并不只是因为好玩,它们将用来解析css和js),html不能简单的用解析所需的上下文无关文法来定义。

    Html有一个正式的格式定义——DTD(Document Type Definition文档类型定义)——但它并不是上下文无关文法,html更接近于xml,现在有很多可用的xml解析器,html有个xml的变体——xhtml,它们间的不同在于,html更宽容,它允许忽略一些特定标签,有时可以省略开始或结束标签。总的来说,它是一种soft语法,不像xml呆板、固执。

    显然,这个看起来很小的差异却带来了很大的不同。一方面,这是html流行的原因——它的宽容使web开发人员的工作更加轻松,但另一方面,这也使很难去写一个格式化的文法。所以,html的解析并不简单,它既不能用传统的解析器解析,也不能用xml解析器解析。

    HTML DTD

    Html适用DTD格式进行定义,这一格式是用于定义SGML家族的语言,包括了对所有允许元素及它们的属性和层次关系的定义。正如前面提到的,html DTD并没有生成一种上下文无关文法。

    DTD有一些变种,标准模式只遵守规范,而其他模式则包含了对浏览器过去所使用标签的支持,这么做是为了兼容以前内容。最新的标准DTD在http://www.w3.org/TR/html4/strict.dtd

    DOM

    输出的树,也就是解析树,是由DOM元素及属性节点组成的。DOM是文档对象模型的缩写,它是html文档的对象表示,作为html元素的外部接口供js等调用。

    树的根是“document”对象。

    DOM和标签基本是一一对应的关系,例如,如下的标签:

    <html>
        <body>
            <p>Hello DOM</p>
            <div>
                <img src=”example.png” />
            </div>
        </body>
    </html>

    将会被转换为下面的DOM树:

    图8:示例标签对应的DOM树

    和html一样,DOM的规范也是由W3C组织制定的。这是使用文档的一般规范。一个模型描述一种特定的html元素。

    这里所谓的树包含了DOM节点是说树是由实现了DOM接口的元素构建而成的,浏览器使用已被浏览器内部使用的其他属性的具体实现。

    解析算法(The parsing algorithm)

    正如前面章节中讨论的,hmtl不能被一般的自顶向下或自底向上的解析器所解析。

    原因是:

    1. 这门语言本身的宽容特性
    2. 浏览器对一些常见的非法html有容错机制
    3. 解析过程是往复的,通常源码不会在解析过程中发生改变,但在html中,脚本标签包含的“document.write”可能添加标签,这说明在解析过程中实际上修改了输入。

    不能使用正则解析技术,浏览器为html定制了专属的解析器。

    Html5规范中描述了这个解析算法,算法包括两个阶段——符号化及构建树。

    符号化是词法分析的过程,将输入解析为符号,html的符号包括开始标签、结束标签、属性名及属性值。

    符号识别器识别出符号后,将其传递给树构建器,并读取下一个字符,以识别下一个符号,这样直到处理完所有输入。

    图9:HTML解析流程

    符号识别算法(The tokenization algorithm)

    算法输出html符号,该算法用状态机表示。每次读取输入流中的一个或多个字符,并根据这些字符转移到下一个状态,当前的符号状态及构建树状态共同影响结果,这意味着,读取同样的字符,可能因为当前状态的不同,得到不同的结果以进入下一个正确的状态。

    这个算法很复杂,这里用一个简单的例子来解释这个原理。

    基本示例——符号化下面的html:

    <html>
        <body>
            Hello world
        </body>
    </html>

    初始状态为“Data State”,当遇到“<”字符,状态变为“Tag open state”,读取一个a-z的字符将产生一个开始标签符号,状态相应变为“Tag name state”,一直保持这个状态直到读取到“>”,每个字符都附加到这个符号名上,例子中创建的是一个html符号。

    当读取到“>”,当前的符号就完成了,此时,状态回到“Data state”,“”重复这一处理过程。到这里,html和body标签都识别出来了。现在,回到“Data state”,读取“Hello world”中的字符“H”将创建并识别出一个字符符号,这里会为“Hello world”中的每个字符生成一个字符符号。

    这样直到遇到“”中的“<”。现在,又回到了“Tag open state”,读取下一个字符“/”将创建一个闭合标签符号,并且状态转移到“Tag name state”,还是保持这一状态,直到遇到“>”。然后,产生一个新的标签符号并回到“Data state”。后面的“”将和“”一样处理。

    图10:符号化示例输入

    树的构建算法(Tree construction algorithm)

    在树的构建阶段,将修改以Document为根的DOM树,将元素附加到树上。每个由符号识别器识别生成的节点将会被树构造器进行处理,规范中定义了每个符号相对应的Dom元素,对应的Dom元素将会被创建。这些元素除了会被添加到Dom树上,还将被添加到开放元素堆栈中。这个堆栈用来纠正嵌套的未匹配和未闭合标签,这个算法也是用状态机来描述,所有的状态采用插入模式。

    来看一下示例中树的创建过程:

    <html>
        <body>
            Hello world
        </body>
    </html>

    构建树这一阶段的输入是符号识别阶段生成的符号序列。

    首先是“initial mode”,接收到html符号后将转换为“before html”模式,在这个模式中对这个符号进行再处理。此时,创建了一个HTMLHtmlElement元素,并将其附加到根Document对象上。

    状态此时变为“before head”,接收到body符号时,即使这里没有head符号,也将自动创建一个HTMLHeadElement元素并附加到树上。

    现在,转到“in head”模式,然后是“after head”。到这里,body符号会被再次处理,将创建一个HTMLBodyElement并插入到树中,同时,转移到“in body”模式。

    然后,接收到字符串“Hello world”的字符符号,第一个字符将导致创建并插入一个text节点,其他字符将附加到该节点。

    接收到body结束符号时,转移到“after body”模式,接着接收到html结束符号,这个符号意味着转移到了“after after body”模式,当接收到文件结束符时,整个解析过程结束。

    图11:示例html树的构建过程

    解析结束时的处理(Action when the parsing is finished)

    在这个阶段,浏览器将文档标记为可交互的,并开始解析处于延时模式中的脚本——这些脚本在文档解析后执行。

    文档状态将被设置为完成,同时触发一个load事件。

    Html5规范中有符号化及构建树的完整算法(http://www.w3.org/TR/html5/syntax.html#html-parser)。

    浏览器容错(Browsers error tolerance)

    你从来不会在一个html页面上看到“无效语法”这样的错误,浏览器修复了无效内容并继续工作。
    以下面这段html为例:

    <html>
        <mytag>
        </mytag>
        <div>
            <p></div>Really lousy HTML</p>
    </html>

    这段html违反了很多规则(mytag不是合法的标签,p及div错误的嵌套等等),但是浏览器仍然可以没有任何怨言的继续显示,它在解析的过程中修复了html作者的错误。

    浏览器都具有错误处理的能力,但是,另人惊讶的是,这并不是html最新规范的内容,就像书签及前进后退按钮一样,它只是浏览器长期发展的结果。一些比较知名的非法html结构,在许多站点中出现过,浏览器都试着以一种和其他浏览器一致的方式去修复。

    Html5规范定义了这方面的需求,webkit在html解析类开始部分的注释中做了很好的总结。

    解析器将符号化的输入解析为文档并创建文档,但不幸的是,我们必须处理很多没有很好格式化的html文档,至少要小心下面几种错误情况。

    1. 在未闭合的标签中添加明确禁止的元素。这种情况下,应该先将前一标签闭合
    2. 不能直接添加元素。有些人在写文档的时候会忘了中间一些标签(或者中间标签是可选的),比如HTML HEAD BODY TR TD LI等
    3. 想在一个行内元素中添加块状元素。关闭所有的行内元素,直到下一个更高的块状元素
    4. 如果这些都不行,就闭合当前标签直到可以添加该元素。

    下面来看一些webkit容错的例子:

    </br>替代<br>

    一些网站使用替代
    ,为了兼容IE和Firefox,webkit将其看作

    代码:

    if (t->isCloseTag(brTag) && m_document->inCompatMode()) {
        reportError(MalformedBRError);
        t->beginTag = true;
    }

    Note -这里的错误处理在内部进行,用户看不到。

    迷路的表格

    这指一个表格嵌套在另一个表格中,但不在它的某个单元格内。

    比如下面这个例子:

    <table>
        <table>
            <tr><td>inner table</td></tr>
        </table>
        <tr><td>outer table</td></tr>
    </table>

    webkit将会将嵌套的表格变为两个兄弟表格:

    <table>
        <tr><td>outer table</td></tr>
    </table>
    
    <table>
        <tr><td>inner table</td></tr>
    </table>

    代码:

    if (m_inStrayTableContent && localName == tableTag)
        popBlock(tableTag);

    webkit使用堆栈存放当前的元素内容,它将从外部表格的堆栈中弹出内部的表格,则它们变为了兄弟表格。

    嵌套的表单元素

    用户将一个表单嵌套到另一个表单中,则第二个表单将被忽略。

    代码:

    if (!m_currentFormElement) {
        m_currentFormElement = new HTMLFormElement(formTag,m_document);
    }

    太深的标签继承

    www.liceo.edu.mx是一个由嵌套层次的站点的例子,最多只允许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;
    }
    
    ### 放错了地方的html、body闭合标签
    
    又一次不言自明。
    
    支持不完整的html。我们从来不闭合body,因为一些愚蠢的网页总是在还未真正结束时就闭合它。我们依赖调用end方法去执行关闭的处理。
    
    代码:
    

    if (t->tagName == htmlTag || t->tagName == bodyTag )
    return;

    
    所以,web开发者要小心了,除非你想成为webkit容错代码的范例,否则还是写格式良好的html吧。
    
    ## CSS解析(CSS parsing)
    
    还记得简介中提到的解析的概念吗,不同于html,css属于上下文无关文法,可以用前面所描述的解析器来解析。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{nmstart}{nmchar}*

    
    “ident”是识别器的缩写,相当于一个class名,“name”是一个元素id(用“#”引用)。
    
    语法用BNF进行描述:
    
    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*] ‘)’ ]
    ;
    说明:一个规则集合有这样的结构
    div.error , a.error {
    color:red;
    font-weight:bold;
    }
    div.error和a.error时选择器,大括号中的内容包含了这条规则集合中的规则,这个结构在下面的定义中正式的定义了:
    ruleset
    selector [ ‘,’ S* selector ]*
    ‘{’ S* declaration [ ‘;’ S* declaration ]* ‘}’ S*
    ;
    “`

    这说明,一个规则集合具有一个或是可选个数的多个选择器,这些选择器以逗号和空格(S表示空格)进行分隔。每个规则集合包含大括号及大括号中的一条或多条以分号隔开的声明。声明和选择器在后面进行定义。

    Webkit CSS解析器(Webkit CSS parser)

    Webkit使用Flex和Bison解析生成器从CSS语法文件中自动生成解析器。回忆一下解析器的介绍,Bison创建一个自底向上的解析器,Firefox使用自顶向下解析器。它们都是将每个css文件解析为样式表对象,每个对象包含css规则,css规则对象包含选择器和声明对象,以及其他一些符合css语法的对象。

    图12:解析css

    处理脚本及样式表的顺序(The order of processing scripts and style sheets)

    脚本

    web的模式是同步的,开发者希望解析到一个script标签时立即解析执行脚本,并阻塞文档的解析直到脚本执行完。如果脚本是外引的,则网络必须先请求到这个资源——这个过程也是同步的,会阻塞文档的解析直到资源被请求到。这个模式保持了很多年,并且在html4及html5中都特别指定了。开发者可以将脚本标识为defer,以使其不阻塞文档解析,并在文档解析结束后执行。Html5增加了标记脚本为异步的选项,以使脚本的解析执行使用另一个线程。

    预解析(Speculative parsing)

    Webkit和Firefox都做了这个优化,当执行脚本时,另一个线程解析剩下的文档,并加载后面需要通过网络加载的资源。这种方式可以使资源并行加载从而使整体速度更快。需要注意的是,预解析并不改变Dom树,它将这个工作留给主解析过程,自己只解析外部资源的引用,比如外部脚本、样式表及图片。

    样式表(Style sheets)

    样式表采用另一种不同的模式。理论上,既然样式表不改变Dom树,也就没有必要停下文档的解析等待它们,然而,存在一个问题,脚本可能在文档的解析过程中请求样式信息,如果样式还没有加载和解析,脚本将得到错误的值,显然这将会导致很多问题,这看起来是个边缘情况,但确实很常见。Firefox在存在样式表还在加载和解析时阻塞所有的脚本,而Chrome只在当脚本试图访问某些可能被未加载的样式表所影响的特定的样式属性时才阻塞这些脚本。

    展开全文
  • 浏览器原理,时序图,DOM树、Render树构建

    上一篇机器学习的博客一直没给补完,然而我现在还是想再挖个坑,浏览器安全…
    这周先补完,再开个论文总结和翻译系列吧。

    言归正传,浏览器安全是归类到web安全中的。

    想想安全行业里最多的就是搞Web安全的人,需求略大、门槛略低,以及这算是离“黑客”二字最近的技术了。说起来有些群里那些初高中的少年还真让我很是羡慕,我们都老了,年轻人才是祖国的未来啊~

    我以前对Web安全的了解也停留在通过注入啊、上传啊这些手段“拿站”,还有owasp10。实际上它是有一个架构和体系的,总的来说,Web安全可以从客户端安全服务器端安全两方面讨论。

    浏览器安全属于Web安全中的客户端安全部分,当然,还有XSS、CSRF、点击劫持等都能算到客户端安全这一类中。而服务端安全包含了SQL注入、文件上传、配置安全、拒绝服务等问题。

    分类来自《白帽子讲Web安全》,看看书的目录就能明白,这里就不上图了。

    关于浏览器原理的文章:《How browsers work》经典

    架构

    浏览器大概分为以下几个部分,实际上,不同浏览器如chrome、firefox等的具体实现会有一些区别。

    这里写图片描述

    用户界面:与用户交互、接受用户操作。
    浏览器引擎:提供接口(加载、刷新、后退等),操作渲染引擎。这样渲染引擎就与平台无关,可以移植了

    渲染引擎:解析HTML和CSS,完成布局和显示。浏览器的核心,这个是要详细介绍的。

    网络:协议解析,网络I/O等
    JavaScript解释器:解析JS代码。也有XML的解释器,不单独列出了。
    用户界面后端:用于绘制基本小部件(如组合框、窗口)。它暴露不是平台特定的通用接口。其下使用操作系统用户界面方法。
    数据存储模块:存cookie、缓存、书签等。


    Chrome从修改开源的Webkit,到自己的Blink渲染引擎;Firefox的Gecko;IE的trident。网上或多或少有些资料,可以看到这些内核在实现上、结构上都有一些区别。

    去年微软新出了Edge,渲染引擎是EdgeHTML,JS引擎是Chakra,都是新的。其中Chakra已经开源。

    比如chrome,从总体结构到各个模块的详细分析,深入研究的资料已经挺多了。所以本文主要对edge进行探索。


    Edge分析

    查阅资料,官方没有直接给出Edge的架构图。但首先可以得到的信息是:①Edge采用的渲染引擎是edgehtml;②Edge采用的JS引擎是chakra,且微软已开源。

    现在需要知道的是,还有哪些动态链接库呢?
    查找前人资料,首先可以知道IE的模块如下图:

    这里写图片描述

    为了得到更多信息,安装win10虚拟机,这个win10的镜像是专用来试用Edge的,没有IE之类多余的东西。

    找到Edge的安装目录,发现安装文件夹下还包含EdgeContent.dll,eview.dll,emodel.dll,edata.dll四个库文件。以及可执行文件有MicrosoftEdge.exe和MicrosoftEdgecp.exe两种。
    这里写图片描述

    要探明dll被调用关系,于是首先使用Process Explorer查看进程调用dll的情况,如图,可以看到MicrosoftEdgecp.exe调用的dll显示在下方:
    这里写图片描述

    最终与浏览器相关的进程包括SearchUI、MicrosoftEdge.exe和MicrosoftEdgecp.exe。其中在ie中就存在的urlmon.dll和wininet.dll都可以被这三个进程调用。另外,MicrosoftEdge.exe会调用的是eview.dll,emodel.dll,edata.dll系列;而MicrosoftEdgecp.exe调用的是EdgeContent.dll、edgehtml.dll系列,以及可以调用js引擎chakra.dll;SearchUI.exe与MicrosoftEdgecp.exe差不多,但是没有调用EdgeConetnt.dll。

    这其中还有一个问题,就是dll之间的相互调用关系。这里使用dependency查看,如图打开EdgeContent.dll:
    这里写图片描述

    查看所有dll后,基本上能得到这几个已知组件的层次。最后自绘一个乱猜的edge架构图供参考,不要当真:
    这里写图片描述

    浏览器事件处理时序

    比如,加载带有JavaScript脚本的HTML文档:

    这里写图片描述

    渲染引擎原理

    渲染的过程如图:(图出自软件安全与脆弱性分析ppt)

    这里写图片描述

    即首先构建DOM树,再结合CSS样式规则构建Render树,最后根据Render树来布局并绘制。

    具体如何生成的呢,比如说,给出如下代码:

    <body>
    <div id="sample">
      <h3>HTML DOM Tree</h3>
      <div id="myDiagramDiv" style="border: 1px solid blue; width:100%; height:300px"></div>
        <p>
            Sample
        </p>
        <p>
            <a href="button.html" target="_blank">Button</a>, 
            click to open <a href="google.com">google</a>.
        </p>
      <p id="lastParagraph">
        Elements
      </p>
      <div id="otherInfo">
        <div id="tableContainer" style="display: inline-block;">
          <table style="border: 1px; border-collapse: collapse;">
            <tbody><tr>
            <th id="firstHeader">Table header</th>
            <th id="secondHeader">Table header 2</th>
            </tr>
          </tbody></table>
        </div>
      </div>
    </div>
    </body>

    DOM树构建

    这里写图片描述

    Render树构建

    这里写图片描述

    展开全文
  • 业界衡量移动端web app交互性能的优劣主要是通过检测webview渲染页面时白屏时间,首屏时间,DOM树构建时间,整页时间,交互性能指Processing和onLoad 在浏览器交互阶段(Processing和onLoad时段)浏览器接收到...

    业界衡量移动端web app交互性能的优劣主要是通过检测webview渲染页面时白屏时间,首屏时间,DOM树构建时间,整页时间交互性能指Processing和onLoad

    在浏览器交互阶段(Processing和onLoad时段)浏览器接收到服务器返回的基础页的数据后,浏览器需要对HTML对这个单纯的文本内容进行解析,从文本中构建出一个内部数据结构DOM树,从HTML也能得到外联和内联css脚本和js脚本,还有媒体文件(图片,视频,声音)都需要再次发起网络请求下载。

    1》白屏时间:

    1)概念:

    白屏时间指的是浏览器开始显示内容的时间,我们一般认为浏览器开始渲染<body>标签或者解析完<head>标签的时刻就是页面白屏结束的时间点

    2)原因:

    弱网络下(2G网络),网络延迟,js加载延迟会阻塞页面

    客户端存在bug,缓存模块错乱,不缓存js等...

    3)解决方法:

    1》加快js执行速度,比如无限滚动的页面,可以使用js先渲染一个屏幕范围内的东西

    2》减少文件加载体积,如hrml压缩,js压缩

    3》在首屏直接同步渲染html,后续的滚屏等再采用异步请求数据和渲染html

    4)统计白屏数量:

    监听某个主DIV的变化(单页面的应用,总会有个入口DIV来监听),白屏就是该DIV没有在规定时间内没有放入东西,所以只要在规定时间内该DIV没有变化,那就可以进行白屏统计

    5)计算白屏时间:

    responseStart-navigationStart

    let timing=performance.timing;

    let start=timing.navigationStart;

    let firstPainttime=0;

    firstPainttime=timing.responseStart-start;

    console.log(firstPainttime)

    2》首屏时间:

    1)概念:

    首屏时间是指用户看到的第一屏,就是网页顶部大小为当前窗口的区域显示完整的时间。

    对用户体验来说首屏时间是用户对一个网站的重要体验因素,通常5秒以内是优秀,10秒以内是可以接受,10秒以上不可忍受。

    2)计算首屏时间:

    页面标签法:适用首屏内容不需要拉取数据才能生存以及页面不考虑图片等资源的加载

    首屏高度内图片加载法:比较符合网页的实际体验并且比较节省设备运行资源

    通常我们首屏内容加载最慢的就是图片资源,因此我们会把首屏内加载最慢的图片的时间当做首屏的时间,因为浏览器对每个页面的TCP连接有限制,使得并不是所有图片都能立刻开始下载和显示。因此我们在DOM树构建完成后将会去遍历首屏内所有图片标签,并监听所有图片的onload事件,最终遍历图片标签的加载时间的最大值,用这个最大值减去navigationStart可获取近似的首屏时间

    3)优化:(除了常规的优化)

    比较通常的页面加载模式:将css放在head标签内,为了避免阻塞将js放在底部,因此页面渲染完成后还需要等待js的加载,js拉取数据以及js的渲染,这大大减慢了首屏及加载时间

    从性能角度看,将加载模式换成下面的模式更有利于首屏的渲染

    首屏优先模式总结为三个原则:

    一是首屏数据拉取逻辑置于顶部,是为了让数据能够第一时间返回,相比起将数据拉取逻辑放在外部资源会少一个js资源加载的往返时间

    二是首屏渲染css及js逻辑优先内联html,是为了当html文档返回时css和js能够立即执行

    三是次屏逻辑延后处理和执行,各种数据上报最好延时处理,这样可以减少阻塞

    3》DOM树构建时间

    指浏览器开始对基础页文件内容进行解析到文本中构建出一个内部数据结构(DOM树)的事件,开发人员创建了domready事件,它在DOM加载之后及资源加载之前被触发,在本地浏览器中以DOMContentLoaded事件的形式被使用

    4》整页时间

    1)整页时间是指页面完成整个加载过程的时刻,

    loadEventEnd-navigationSart

    2)在传统采集方法中会使用window的onload事件来记录时间戳

     

     

    展开全文
  • 树构建阶段,以 Document 为根节点的 DOM 树也会不断进行修改,向其中添加各种元素。标记生成器发送的每个节点都会由树构建器进行处理。规范中定义了每个标记所对应的 DOM 元素,这些元素会在接收到相应的标记时...

    在创建解析器的同时,也会创建 Document 对象。在树构建阶段,以 Document 为根节点的 DOM 树也会不断进行修改,向其中添加各种元素。标记生成器发送的每个节点都会由树构建器进行处理。

    规范中定义了每个标记所对应的 DOM 元素,这些元素会在接收到相应的标记时创建。这些元素不仅会添加到 DOM 树中,还会添加到开放元素的堆栈中。此堆栈用于纠正嵌套错误和处理未关闭的标记。其算法也可以用状态机来描述。这些状态称为“插入模式”。

    让我们来看看示例输入的树构建过程:

    Hello world

    树构建阶段的输入是一个来自标记化阶段的标记序列。

    第一个模式是“initial mode”。接收 HTML 标记后转为“before html”模式,并在这个模式下重新处理此标记。这样会创建一个 HTMLHtmlElement 元素,并将其附加到 Document 根对象上。

    然后状态将改为“before head”。此时我们接收“body”标记。即使我们的示例中没有“head”标记,系统也会隐式创建一个 HTMLHeadElement,并将其添加到树中。

    现在我们进入了“in head”模式,然后转入“after head”模式。系统对 body 标记进行重新处理,创建并插入 HTMLBodyElement,同时模式转变为“body”。

    现在,接收由“Hello world”字符串生成的一系列字符标记。接收第一个字符时会创建并插入“Text”节点,而其他字符也将附加到该节点。

    接收 body 结束标记会触发“after body”模式。现在我们将接收 HTML 结束标记,然后进入“after after body”模式。接收到文件结束标记后,解析过程就此结束。

    c11c9ab43d20438cc5211c2fa81d2d84.gif

    示例 HTML 的树构建

    解析结束后的操作

    在此阶段,浏览器会将文档标注为交互状态,并开始解析那些处于“deferred”模式的脚本,也就是那些应在文档解析完成后才执行的脚本。然后,文档状态将设置为“完成”,一个“加载”事件将随之触发。

    展开全文
  • WebKit之DOM树构建流程分析

    千次阅读 2015-12-04 00:03:08
    今天关注webkit中dom树是怎么构建的,HTML是怎么分析的。 1、dom相关的代码在webcore中dom目录下,有很多类,比较重要的是 Document.h、DocumentFragment.h、DocumentParser.h DocumentParser是一个基类...
  • 上一篇文章我们讲了chrome性能面板的使用,了解了请求过程中的几个性能指标,这篇文章我们一起来看一下DOM树是如何生成的,本文主要有两大块内容:第一个是解析过程中遇到JavaScript脚本,DOM解析器是如何处理的?...
  • 解析与DOM树构建之解析规则

    千次阅读 2015-06-26 22:55:37
    解析的结果通常是一个呈现文档结构的节点,一般称之为解析或句法。 例如,对表达式“2+3-1” 的解析会得到以下结构 解析语法规则 解析过程是基于文档内容所遵从的语法规则的,也就是以某种语言或格式写...
  • HTML解析器的任务是将HTML标记解析成解析。 HTML的词汇和语法在W3C规范中进行了定义。 ... 解析是由DOM(Document Object Model)元素和属性节点构成的结构,根节点是Document对象。 DOM与标记是一一对应的。
  • 解析的结果通常是表达文档结构的节点,称为解析或语法。 例如,解析2+3-1表达式,会返回解析: 解析是以文档所遵循的规则为基础的。规则包括词汇表和语法规则。解析的过程可以分成:词法分析(Lexical ...
  • 一个级联样式表(CSS)是由一系列的规则组成的,每一条规则是由一个选择器和若干条声明组成的。每条声明是一个键值对,由属性和值组成。   ... CSS是上下文无关的语法,可以使用自上而下解析器或自下而上解析器...
  • 在应用样式的时候,不会更改DOM树,因此解析样式表的时候也不会停止文档解析。 2 脚本 解析器遇到标记时,立即解析并执行脚本。一旦发现有脚本文件的引用,就必须等待脚本文件下载完。这时,文档的解析会...
  • DOM树构建的同时,浏览器会构建渲染树(render tree)。渲染树的节点(渲染器),在Gecko中称为frame,而在webkit中称为renderer。渲染器是在文档解析和创建DOM节点后创建的,会计算DOM节点的样式信息。  在...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 44,533
精华内容 17,813
关键字:

dom树构建