zoukankan      html  css  js  c++  java
  • 浏览器是怎样工作的二:渲染引擎 HTML解析(4)(转)

    本文作者:hfliu

    文章来源:携程UED

    解析结束后的动作

    在这一阶段浏览器会把文档标记为交互模式,并开始解析deferred模式的script。"deferred"意味着脚本应该在文档解析完成后执行。脚本处理完成后将进入"complete"状态,"load"事件发生。

    HTML5规范中包含了完整的算法: http://www.w3.org/TR/html5/syntax.html#html-parser

    浏览器的容错

    你永远不会看到HTML页面语法错误。浏览器会修正错误并继续。看看下面的例子:

    1. <html>  
    2.     <mytag>  
    3.     mytag>  
    4.     <div>  
    5.           <p>    
    6.     div>  
    7.         Really lousy HTML   
    8.     p>  
    9.  html>  

    我一定违背了几百万条规则("my tag"是非法标签,"p"与"p"元素嵌套错误等等),但浏览器仍然正确地显示,没有任何抱怨。所以很多解析器代码在修正这些HTML作者的错误。

    浏览器的错误处理相当统一,惊人的是这并不是当前HTML规范的一部分,就像书签、前进、后退,只是多年以来在浏览器中开发出来的。有些无效的HTML结构出现在许多网站,浏览器会尝试用和其它各种浏览器一致的方式修复这些错误。

    HTML5规范中应这一需求定义了一些东西,Webkit在它的HTML解析器类开头的注释中很好的做了摘要:

    解析器分析输入符号生成文档,并构建文档树。如果文档格式良好,解析工作会很简单。

    不幸的是,我们要处理很多格式不良的HTML文档,解析器需要宽容这些错误。

    我们至少需要照顾下列错误:

    1. 元素必需被插入在正确的位置。未关闭的标签应该一一关闭,直到可以添加新元素。

    2. 不允许直接添加元素。用户可能会漏掉一些标签,比如:HTML HEAD BODY TBODY TR TD LI(我遗漏了什么?)。

    3. 在inline元素里添加block元素时,应关闭所有inline元素,再添加block元素。

    4. 如果以上不起作用,关闭所有元素,直到可以添加,或者忽略此标签。

    让我们来看一些Webkit容错的例子:

    使用
    代替
    有些站点使用
    而不是
    。为了更好的与IE和Firefox兼容,Webkit将其视为
    。代码如下:

    使用</br>代替<br>
    有些站点使用</br>而不是<br>。为了更好的与IE和Firefox兼容,Webkit将其视为<br>。代码如下:

    1. if (t->isCloseTag(brTag) && m_document->inCompatMode()) {   
    2.      reportError(MalformedBRError);   
    3.      t->beginTag = true;   
    4. }  

    注意,这里的错误处理是内部的,并不会显示给用户。

    迷失的表格

    像下面的例子这样,一个表格包含在另外一个表格的内容中,但不是在外部表格的单元格里:

    1. <table>  
    2.     <table>  
    3.         <tr><td>inner tabletd>tr>  
    4.          table>  
    5.     <tr><td>outer tabletd>tr>  
    6.  table>  

    Webkit会改变层级关系,把它们处理成两个相临的表格:

    1. <table>  
    2.     <tr><td>outer tabletd>tr>  
    3.  table>  
    4.  <table>  
    5.     <tr><td>inner tabletd>tr>  
    6.  table>  

    代码:

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

    Webkit用一个堆栈保存当前元素,它会把里面的表格弹出到外部表格堆栈,使它们成为兄弟表格。

    元素嵌套

    为防止一表单的嵌套,第二个表单会被忽略。代码:

    1. if (!m_currentFormElement) {   
    2.         m_currentFormElement = new HTMLFormElement(formTag,    m_document);   
    3. }  

    过深的元素层级

    注释不言自喻:

    www.liceo.edu.mx是一个层级过深的典型,它用大量的嵌套到1500个标签的深度。我们只允许同一标签连续出现20次,超过的话,所有此标签都会被忽略。

    1. bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName)   
    2. {   
    3. unsigned i = 0;   
    4.  for (HTMLStackElem* curr = m_blockStack;   
    5.          i < cMaxRedundantTagDepth && curr && curr->tagName == tagName;   
    6.      curr = curr->next, i++) { }   
    7.  return i != cMaxRedundantTagDepth;   
    8. }  

    错误的html或body结束标签位置

    注释仍然很明了:

    支持真正的错误html 我们永远不关闭tag,因为有些愚蠢的网页在文档真正结束之前就关闭了它。 让我们用end()来关闭标签。
    1. if (t->tagName == htmlTag || t->tagName == bodyTag )   
    2.         return;  

    所以网页作者们小心了,除非你想写一个Webkit容错的示例代码,否则请按正确格式书写HTML。

  • 相关阅读:
    Linux Namespace : IPC
    Linux Namespace : UTS
    Linux Namespace : 简介
    《Two Dozen Short Lessons in Haskell》(二十四)代数类型
    为期近五个月的英语培训班总结
    GTD实践2周年后一些体会
    读书笔记2013第10本:《学得少却考得好Learn More Study Less》
    读书笔记2013第9本:《注意力曲线----打败分心与焦虑》
    《Two Dozen Short Lessons in Haskell》(二十二)递归
    GIF图片合集(用于网络请求图片用)
  • 原文地址:https://www.cnblogs.com/fxie/p/2862766.html
Copyright © 2011-2022 走看看