我们前面说过,HTML 无法用常规的自上而下或自下而上的解析器进行解析。为什么呢?
原因在于:
语言的宽容本质。
浏览器历来对一些常见的无效 HTML 用法采取包容态度。
解析过程需要不断地反复。源内容在解析过程中通常不会改变,但是在 HTML 中,脚本标记如果包含 document.write,就会添加额外的标记,这样解析过程实际上就更改了输入内容。
由于不能使用常规的解析技术,浏览器就创建了自定义的解析器来解析 HTML。
HTML5 规范详细地描述了解析算法。此算法由两个阶段组成:标记化和树构建。
标记化是词法分析过程,将输入内容解析成多个标记。HTML 标记包括起始标记、结束标记、属性名称和属性值。
标记生成器识别标记,传递给树构造器,然后接受下一个字符以识别下一个标记;如此反复直到输入的结束。
HTML 解析流程
一些题外话
PS:如果要你设计一个浏览器,这个HTML解析处于哪个阶段?
从整个浏览器的工作周期来看,一款浏览器大概需要这么几个模块:
1. 首先是联网模块。包括域名解析(这个可以忽略)、发起请求,连接线程的管理等(单线程请忽略)。
2. 然后是解析模块。包括了html的解析、DOM树的建立等。尤其是html的解析,会涉及到容错方面的考虑,DOM树要考虑各种场景下的效率(效率可以先不考虑)。
3. 接下来是渲染模块。根据你建立的DOM树,按照网页所描述的内容展示字体、色块等,这个没什么好说的。
4. 还有其他,比如网页对象的管理、页面事件的响应(那些OnClick什么的,好吧我不知道这个是不是html1.0里的东西)插件管理(flash和java,好吧这些范围又大了)。
有了以上,差不多应该就是一个浏览器内核了。真正的浏览器内核开发,那涵盖的知识领域太多了,编译原理、分布式计算、网络编程、图形图像等,还是比较复杂的。
当然对于整体而言,了解浏览器的工作方式也是很有趣的事儿。