出自:
http://gent.ilcore.com/2011/05/how-web-page-loads.html当html代码块(chunk)一旦有效,html parser开始处理它,将标签解析成token形式,如输入<b>hello</b>, 解析成:
start-tag { name: b }
character { data: h }
character { data: e }
character { data: l }
character { data: l }
character { data: o }
end-tag { name: b }
所有token是串行生成的,然后依次送到tree builder,tree builder根据它动态修改DOM tree。
子资源(subresources)
tree builder频繁做的事是创建html元素然后插到文档中。有一些元素会触发加载子资源:
<applet archive>
<audio src>
<body background>
<embed src>
<frame src>
<html manifest>
<iframe src>
<img src>
<input type=image src>
<link href>
<object data>
<script src>
<source src>
<track src>
<video poster>
<video src>
解析算法会尽可能高效的将html源码转成DOM tree。但遇到end-tag { name: script }的token时,处理会不同。如果script没有defer或async属性,它会执行脚本。
执行前还要满足两个条件:
1. 如果是外联的JS,必须等完全下载完再执行
2. 为了执行JS,页面中所有的样式表必须完全下载完
因为脚本有可能改变DOM,这会影响后面的解析,所以parser必须停下来。为什么还要等css? css会影响节点的样式(如宽高),JS很有可能会访问节点这些受css影响的属性。
了解这一特点就知道应该怎么正确放置CSS和JS。
减少阻塞parser
当parser被阻塞时,webkit会启动一个轻量的parser叫preload scanner(
http://gent.ilcore.com/2011/01/webkit-preloadscanner.html),它通过预扫描和加载某些可能需要的子资源来缓解parser阻塞的问题。其它浏览器也有类似优化。
来自
http://www.douban.com/note/153864670/作者提示这种机制,仍不能解除parser的阻塞,结点在js执行完成前仍不能添加到DOM tree上。创建完DOM tree还需转成render tree,然后再layout和paint。所以,意味阻塞过程中结点是显示不出来的。
当parser完成,所有脚本执行完,触发DOMContentLoaded事件。接下来,parser会继续等async属性的脚本下载完并执行。当所有子资源下载完,触发load事件。