草庐IT

javascript - 何时解析HTML DOM树?

coder 2023-07-31 原文

我总是看到网页的渲染流程,如下图所示:


因此,绘画仅在解析DOM树并创建CSSOM之后才开始,对吗?另一句话是,最佳做法是将<script>放在<body>的末尾,以便页面在下载脚本之前呈现某些内容。

我的问题是,何时解析DOM树会发生,我们如何说它完成了?以我的理解,最后的<script>也是DOM树的一部分,只有加载脚本后,我们才能调用DOM树。浏览器从上到下读取html文件,创建DOM树,当看到<script>时,它将停止下载并执行它,直到解析遍历整个页面为止。或者,页面是在解析DOM树的同时绘制页面吗?

最佳答案

TL; DR:收到文档后,分析立即开始
解析和绘画
有关更详细的说明,我们需要深入研究渲染引擎的工作方式。
渲染引擎解析HTML文档并创建两棵树:content treerender tree。内容树包含所有DOM节点。渲染树包含所有样式信息(CSSOM),并且仅包含渲染页面所需的DOM节点。
一旦创建了渲染树,浏览器就会经历两个过程:在每个DOM节点上应用layoutpainting。应用布局意味着计算DOM节点应出现在屏幕上的确切坐标。绘画意味着实际渲染像素并应用样式属性。
这是一个循序渐进的过程:浏览器不会等到所有HTML解析完毕后再进行。部分内容将被解析和显示,而该过程将继续处理其余部分内容,这些其余内容始终来自网络。
您可以在浏览器中看到此过程。例如,打开Chrome开发者工具并加载您选择的网站。

Network选项卡中记录 Activity 之后,您会注意到在下载文档时开始解析。它识别资源并开始下载。蓝色垂直线表示DOMContentLoaded事件,红色垂直线表示load事件。

记录时间轴可让您更深入地了解幕后情况。我以上面的屏幕截图为例,以表明在解析文档时会进行绘制。请注意,初始绘制恰好发生在它继续解析文档的另一部分之前。此过程一直持续到到达文档末尾。
单螺纹
呈现引擎是单线程的。除了网络操作之外,几乎所有事情都在此线程中发生。
将其与网络的同步特性结合起来。开发人员希望<script>能够立即解析和执行(即:解析器到达脚本标签后立即执行)。这意味着:

  • 必须从网络中获取资源(由于DNS查找和连接速度,这可能是一个缓慢的过程)。
  • 资源的内容传递给Javascript解释器。
  • 解释器解析并执行代码。

  • 解析文档将暂停,直到此过程完成。通过在文档末尾添加<script>,不会缩短总解析时间。它的确增强了用户体验,因为解析和绘画过程不会被需要执行的<script>中断。
    通过用defer和/或async标记资源,可以解决此问题。 async在HTML解析期间下载文件,并在完成下载后暂停HTML解析器以执行该文件。 defer在HTML解析期间下载文件,并且仅在解析器完成后才执行。
    投机解析
    一些浏览器旨在通过使用所谓的推测性解析来解决<script>的阻塞方面。在下载和执行脚本时,引擎会向前解析(并运行HTML树构造!)。 Firefox和Chrome使用此技术。
    您可以想象,如果推测成功(例如,文档中包含的脚本未更改DOM),则性能会提高。无需等待脚本执行,页面已成功绘制。
    不利的一面是,当猜测失败时,将会有更多的工作丢失。
    对我们来说幸运的是,非常聪明的人正在使用这些技术,因此即使正确使用document.write也不会破坏该过程。另一个经验法则是不要使用document.write。例如,它可能会破坏投机树:
    // Results in an unbalanced tree
    <script>document.write("<div>");</script>
    
    // Results in an unfinished token
    <script>document.write("<div></div");</script>
    
    进一步阅读
    以下资源值得您阅读:
  • Web Fundamentals(Google Developers)
  • How browsers work
  • HTML5 Parser上的
  • MDN
  • An introduction to Browser Rendering(视频)
  • 关于javascript - 何时解析HTML DOM树?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34269416/

    有关javascript - 何时解析HTML DOM树?的更多相关文章

    1. Ruby 解析字符串 - 2

      我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

    2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

      我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

    3. ruby - 用逗号、双引号和编码解析 csv - 2

      我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

    4. ruby-on-rails - 我更新了 ruby​​ gems,现在到处都收到解析树错误和弃用警告! - 2

      简而言之错误:NOTE:Gem::SourceIndex#add_specisdeprecated,useSpecification.add_spec.Itwillberemovedonorafter2011-11-01.Gem::SourceIndex#add_speccalledfrom/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91./opt/local/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/rails/gem_dependency.rb:275:in`==':und

    5. ruby - 用 YAML.load 解析 json 安全吗? - 2

      我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("

    6. ruby-on-rails - Sphinx - 何时对字段使用 'has' 和 'indexes' - 2

      我几天前在我的ruby​​onrails2.3.2上安装了Sphinx和Thinking-Sphinx,基本搜索效果很好。这意味着,没有任何条件。现在,我想用一些条件过滤搜索。我有公告模型,索引如下所示:define_indexdoindexestitle,:as=>:title,:sortable=>trueindexesdescription,:as=>:description,:sortable=>trueend也许我错了,但我注意到只有当我将:sortable=>true语法添加到这些属性时,我才能将它们用作搜索条件。否则它找不到任何东西。现在,我还在使用acts_as_tag

    7. ruby - 如何使用 Nokogiri 解析纯 HTML 表格? - 2

      我想用Nokogiri解析HTML页面。页面的一部分有一个表,它没有使用任何特定的ID。是否可以提取如下内容:Today,3,455,34Today,1,1300,3664Today,10,100000,3444,Yesterday,3454,5656,3Yesterday,3545,1000,10Yesterday,3411,36223,15来自这个HTML:TodayYesterdayQntySizeLengthLengthSizeQnty345534345456563113003664354510001010100000344434113622315

    8. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

      我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

    9. python - 帮我找到合适的 ruby​​/python 解析器生成器 - 2

      我使用的第一个解析器生成器是Parse::RecDescent,它的指南/教程很棒,但它最有用的功能是它的调试工具,特别是tracing功能(通过将$RD_TRACE设置为1来激活)。我正在寻找可以帮助您调试其规则的解析器生成器。问题是,它必须用python或ruby​​编写,并且具有详细模式/跟踪模式或非常有用的调试技术。有人知道这样的解析器生成器吗?编辑:当我说调试时,我并不是指调试python或ruby​​。我指的是调试解析器生成器,查看它在每一步都在做什么,查看它正在读取的每个字符,它试图匹配的规则。希望你明白这一点。赏金编辑:要赢得赏金,请展示一个解析器生成器框架,并说明它的

    10. ruby - 如何用 Nokogiri 解析连续的标签? - 2

      我有这样的HTML代码:Label1Value1Label2Value2...我的代码不起作用。doc.css("first").eachdo|item|label=item.css("dt")value=item.css("dd")end显示所有首先标记,然后标记标签,我需要“标签:值” 最佳答案 首先,您的HTML应该有和中的元素:Label1Value1Label2Value2...但这不会改变您解析它的方式。你想找到s并遍历它们,然后在每个你可以使用next_element得到;像这样:doc=Nokogiri::HTML(

    随机推荐