经过上两篇的翻译内容(第一篇 , 第二篇),这里做一点小小的深入和整理
重温一下这个过程:

原数据(Bytes)->字符(Characters)
这一步不想多说啥了,现在基本写个网络应用,都有这一步
字符(Characters)->标记(tokens)
比如我们有html文本内如如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div>
<h1 class="title">demo</h1>
<input value="hello">
</div>
</body>
</html>
那变成tokens后,如下:
tagName: html |type: DOCTYPE |attr: |text: "
tagName: |type: Character |attr: |text: \n"
tagName: html |type: startTag |attr: |text: "
tagName: |type: Character |attr: |text: \n"
tagName: head |type: startTag |attr: |text: "
tagName: |type: Character |attr: |text: \n "
tagName: meta |type: startTag |attr:charset=utf-8 |text: "
tagName: |type: Character |attr: |text: \n"
tagName: head |type: EndTag |attr: |text: "
tagName: |type: Character |attr: |text: \n"
tagName: body |type: startTag |attr: |text: "
tagName: |type: Character |attr: |text: \n "
tagName: div |type: startTag |attr: |text: "
tagName: |type: Character |attr: |text: \n "
tagName: h1 |type: startTag |attr:class=title |text: "
tagName: |type: Character |attr: |text: demo"
tagName: h1 |type: EndTag |attr: |text: "
tagName: |type: Character |attr: |text: \n "
tagName: input |type: startTag |attr:value=hello |text: "
tagName: |type: Character |attr: |text: \n "
tagName: div |type: EndTag |attr: |text: "
tagName: |type: Character |attr: |text: \n"
tagName: body |type: EndTag |attr: |text: "
tagName: |type: Character |attr: |text: \n"
tagName: html |type: EndTag |attr: |text: "
tagName: |type: Character |attr: |text: \n"
tagName: |type: EndOfFile |attr: |text: "
- 好细致,连空格和换行都不放过
- 可以重点观察一下,token的顺序,以及标签开闭节点之间的关系。
- 有了一个分类,chrome里分为如下之类:
enum TokenType {
Uninitialized,
DOCTYPE,
StartTag,
EndTag,
Comment,
Character,
EndOfFile,
};
标记(tokens)->节点(node)
事实上,构建DOM的过程中,不是等所有Token都转换完成后再去生成节点对象,而是一边生成Token一边消耗Token来生成节点对象,处理token大致如下:
void HTMLTreeBuilder::processToken(AtomicHTMLToken* token) {
if (token->type() == HTMLToken::Character) {
processCharacter(token);
return;
}
switch (token->type()) {
case HTMLToken::DOCTYPE:
processDoctypeToken(token);
break;
case HTMLToken::StartTag:
processStartTag(token);
break;
case HTMLToken::EndTag:
processEndTag(token);
break;
//othercode
}
}
节点(node)->DOM
构建DOM主要就是建立起每个结点的父子兄弟关系,更多细节,看下面链接里的文章。
以上大部分内容取自这里
这里在加一些内容:
-
在构建DOM的过程中,如果遇到link的标签,当把它插到DOM里面之后,就会触发资源加载,不会影响DOM树的构建,只是说在CSS没处理好之前,构建好的DOM并不会显示出来(渲染时中断)
-
在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建(Dom构建时中断)
-
如果有CSS正在处理中,这时候又来了JS,那DOM暂停(要等JS),JS也不会执行(要等CSSOM)。等CSS处理完后,JS再执行,等JS执行完后,DOM再继续。
-
JS的执行要等待位于其前面的CSS和JS加载、执行完。
【未完待续】。。。