chromium DOM树形成浅析

转载,请标注: from 你吧吧

当主资源load下来,我们来看看chromium如何去解析主资源,构建DOM树的。

整个DOM的创建过程比较复杂,这里简单分析下,如何将网络中download的资源,进行DOM树的解析构建过程的。

当主资源加载完,准确的讲,在主资源还没加载完,但是sandbox process已经收到从 browser process的部分主资源内容的时候,就开始了DOM树的构建。

我们这里从“sandbox process已经收到从 browser process的部分主资源内容”,这个时刻开始说起。

1. ResourceLoader.cpp文件的方法:ResourceLoader::didReceiveData,这是sandbox process收到了部分主资源

该方法中有代码:m_resource->appendData(data, length);

2. 上代码执行的是文件:RawResource.cpp中方法:RawResource::appendData

该方法中有代码:

while (RawResourceClient* c = w.next())

c->dataReceived(this, data, length);

3. 这里会调用DocumentLoader.cpp文件中方法:DocumentLoader::dataReceived

该方法中有代码:commitData(data, length);

执行的是同文件中方法:DocumentLoader::commitData

4. 上面提到的方法中有代码:m_writer->addData(bytes, length);

执行的是文件DocumentWriter.cpp文件中方法:DocumentWriter::addData

该方法中有代码:m_parser->appendBytes(bytes, length);

执行的是文件HTMLDocumentParser.cpp中方法:HTMLDocumentParser::appendBytes

从这个方法开始,则开始了复杂的Dom树的解析过程。

总体上说,从网络中读到的主资源以字符串的形式存在内存中,chromium内核(或者说blink内核)

如何将这些字符串流分析成一个个html 的标签呢?我们看下面的逻辑分析。

5. 在方法:HTMLDocumentParser::appendBytes中有代码:

HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::appendRawBytesFromMainThread, m_backgroundParser, buffer.release()));

这里执行的调用文件 
BackgroundHTMLParser.cpp中方法:BackgroundHTMLParser::appendRawBytesFromMainThread

6. 该方法又会调用同文件中方法:BackgroundHTMLParser::updateDocument。该方法中有代码:

appendDecodedBytes(decodedData);

该代码调用的是同文件种方法:BackgroundHTMLParser::appendDecodedBytes

我们看看该方法:

void BackgroundHTMLParser::appendDecodedBytes(const String& input)
{
    ASSERT(!m_input.current().isClosed());
    m_input.append(input);
    pumpTokenizer();
}

这里会将多个主资源部分 都保存在变量 m_input中。

并调用同文件中方法:BackgroundHTMLParser::pumpTokenizer()

7. 上面的这个方法比较关键,贴出源码看看

void BackgroundHTMLParser::pumpTokenizer()
{
       // No need to start speculating until the main thread has almost caught up.
    if (m_input.totalCheckpointTokenCount() > outstandingTokenLimit)
        return;

    while (true) {
        m_sourceTracker.start(m_input.current(), m_tokenizer.get(), *m_token);
        if (!m_tokenizer->nextToken(m_input.current(), *m_token)) {
            WTF_LOG(Vnbo,"vnbo BackgroundHTMLParser::pumpTokenizer() 1");
            // We've reached the end of our current input.
            sendTokensToMainThread();
            break;
        }
        m_sourceTracker.end(m_input.current(), m_tokenizer.get(), *m_token);

        {
            TextPosition position = TextPosition(m_input.current().currentLine(), m_input.current().currentColumn());

            if (OwnPtr<XSSInfo> xssInfo = m_xssAuditor->filterToken(FilterTokenRequest(*m_token, m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) {
                xssInfo->m_textPosition = position;
                m_pendingXSSInfos.append(xssInfo.release());
            }

            CompactHTMLToken token(m_token.get(), TextPosition(m_input.current().currentLine(), m_input.current().currentColumn()));

            m_preloadScanner->scan(token, m_input.current(), m_pendingPreloads);

            m_pendingTokens->append(token);

        }

        m_token->clear();

        if (!m_treeBuilderSimulator.simulate(m_pendingTokens->last(), m_tokenizer.get()) || m_pendingTokens->size() >= pendingTokenLimit) {
            sendTokensToMainThread();
            // If we're far ahead of the main thread, yield for a bit to avoid consuming too much memory.
            if (m_input.totalCheckpointTokenCount() > outstandingTokenLimit)
                break;
        }
    }
}

我们看看这个true循环中的逻辑。

在true循环中,会一直调用:HTMLSourceTracker.cpp中方法:HTMLSourceTracker::start和HTMLSourceTracker::end以及文件HTMLTokenizer.cpp中方法:HTMLTokenizer::nextToken

其大体逻辑是如此:

1). 从输入的字符串中依次读取,当读到<字符和>字符的时候,内核认为这两个符号之间的内容是一个自然字符串段。并记载下解析到的位置(文件HTMLToken.h中方法:setBaseOffset)。下次读取的时候,再从输入字符串的该位置读取。

2). 遇到<字符,如果该字符后面没有/字符,则认为是一个新的标签开始;如果<字符后面有/字符,则认为与之前的<字符之间的内容是一个标签。

3). 标签之间存在父子关系。

网上有个blog:http://blog.csdn.net/bertzhang/article/details/6695804 对这一点有较好的讲解。

4). 在主资源的解析过程中,遇到标签如 <script>、<img>标签等等,则会异步加载子资源。

8. true循环中还会CompactHTMLToken对象,然后将所有CompactHTMLToken对象保存到m_pendingTokens变量中。

当所有标签都打上token之后,会调用同文件中方法:BackgroundHTMLParser::sendTokensToMainThread()

并且跳出true循环。

9. 上面提到的方法,会调用文件:HTMLDocumentParser.cpp中方法:

HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser

10. 上面方法会调用同文件中方法:HTMLDocumentParser::pumpPendingSpeculations()

该方法会调用同文件中方法:HTMLDocumentParser::processParsedChunkFromBackgroundParser

11. 上面方法会调用同文件种方法:HTMLDocumentParser::constructTreeFromCompactHTMLToken

在这个方法中有代码:m_treeBuilder->constructTree(&token);

时间: 2024-10-02 01:11:33

chromium DOM树形成浅析的相关文章

DOM事件模型浅析

1.何为DOM DOM是"Document Object Model"的缩写,中文译为"文档对象模型".它是一种跨平台.跨语言的编程接口,将HTML,XHTML,XML文档映射成树形结构,树的每一个节点都是一个对象.正因如此,面向对象的编程语言(如javascript)可以通过DOM对HTML,XHTML,XML文档进行操作.对于HTML文档来说,它的根结点为document对象,HTML元素为element对象,HTML元素的属性为attr对象. 2.何为DOM事

dom转换成jquery对象

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <meta http-equiv="Content-Type"

JQuery 学习笔记--02

JS 中的 window.onload() 方法与 Jquery 中的 $(document).read(function( ){  }) 的区别 : 加载时机不一样, window.onload()要等所有文件都加载完毕 ( js , css 文件 , 以及图片资源 ) , 而 Jquery 的方法只需要等 DOM 树形成即可 ; $(document).read(function( ){  }) 可简写为 $(function( ) {  }) ; $(document).read(func

渲染树render tree

CSSOM树和DOM树连接在一起形成一个render tree,渲染树用来计算可见元素的布局并且作为将像素渲染到屏幕上的过程的输入. DOM树和CSSOM树连接在一起形成render tree . render tree只包含了用于渲染页面的节点 布局计算了每一个对象的准确的位置以及大小 绘画是最后一步,绘画要求利用render tree来将像素显示到屏幕上 第一步是结合DOM树和CSSOM树形成“render tree”,渲染树用来描述所有可见的DOM内容,并且将CSSOM样式信息附加到节点上

页面渲染1——创建对象模型

Before the browser can render the page it needs to construct the DOM and CSSOM trees. As a result, we need to ensure that we deliver both the HTML and CSS to the browser as quickly as possible. 在页面进行渲染之前,页面会创建DOM和CSSOM树,所以我们要确保尽快的给浏览器传送HTML和CSS. Byte

jQuery实战:认识jQuery的点点滴滴

在这个章节我们可以学到以下的知识: ①为什么应当使用jQuery? ②jQuery的基本原理和概念 ③怎样使用jQuery? 为什么是jQuery? 曾经利用JavaScript试着给页面增添动态的功能,就会发现都遵循着这样的一种模式:选择一个元素或者一组元素,然后可以给它绑定事件和添加效果,例如显示和隐藏,添加css类或者修改元素的特性等等. 利用原始的JavaScript完成这些任务中的任何一个,都会需要用到数十行代码.jQuery的创造者为了使这些常见的任务变得简单而特意地创造了jQuer

JavaScript&amp;jQuery.HTML5事件

HTML5事件 事件 说明 DOMContentLoaded 在DOM树形成后触发(与此同时,图片.CSS和JavaScript可能还在加载).在这个事件中,脚本运行要早于load事件,因为load事件会等待所有资源(比如图片或广告)加载完之后才触发.这种方式会让页面看起来加载速度更快. hashchange 当URL的hash值变化时(不会造成整个窗口刷新)触发.hash值通常在链接中用来指定不同的部分(也被称作为锚点),在使用AJAX加载的页面内容中也会被使用. beforeunload 当

xml语法、DTD约束xml、Schema约束xml、DOM解析xml

今日大纲 1.什么是xml.xml的作用 2.xml的语法 3.DTD约束xml 4.Schema约束xml 5.DOM解析xml 1.什么是xml.xml的作用 1.1.xml介绍 在前面学习的html语言,html是超文本标记语言,使用html语言规定好的标签来封装文本数据.而html使用的标签html语言规定好的,每个标签都有自己特定的功能. xml语言,可扩展的标记语言,这门语言它没有定义任何的标记,而标记是由使用者自己来定义,但是由于标签名称以及属性名称都由用户自己来命名,导致别人在使

[译] 什么阻塞了 DOM?

原文地址:https://www.keycdn.com/blog/blocking-the-dom/原文作者:BRIAN JACKSON 当我们谈到web性能或者优化页面级别的速度时,非常重要的一点是要理解HTML和一个页面是如何在浏览器中构造的,这样你才能找到由于渲染阻塞导致的页面加载延迟.在这篇文章中,我们会深入了解是 什么阻塞了DOM 以及你应该怎样避免这种情况. 什么是DOM? DOM是Document Object Model(文档对象模型)的缩写.它是为HTML和XML定义的一个编程