码迷,mamicode.com
首页 > 其他好文 > 详细

chromium DOM树形成浅析

时间:2015-01-27 11:09:16      阅读:474      评论:0      收藏:0      [点我收藏+]

标签:chromium   blink   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);

 



chromium DOM树形成浅析

标签:chromium   blink   dom树解析   

原文地址:http://blog.csdn.net/u011882998/article/details/43154067

(0)
(2)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!