Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 什么时候解析HTML DOM树?_Javascript_Html_Dom - Fatal编程技术网

Javascript 什么时候解析HTML DOM树?

Javascript 什么时候解析HTML DOM树?,javascript,html,dom,Javascript,Html,Dom,我总是看到网页的呈现流,如下图所示: 因此,只有在解析DOM树并创建CSSOM之后,才能开始绘制,对吗?另一种说法是,将放在的末尾是最好的做法,这样页面在下载脚本之前呈现一些内容 我的问题是,解析DOM树是什么时候发生的,我们怎样才能说它完成了呢?在我的理解中,最终也是DOM树的一部分,只有在加载的脚本中我们才能调用DOM树。浏览器从上到下读取html文件,创建DOM树,当它看到时,它停止下载并执行它,直到解析完成整个页面。或者,页面是否在解析DOM树的同时绘制页面?这实际上取决于浏览器加载所

我总是看到网页的呈现流,如下图所示:

因此,只有在解析DOM树并创建CSSOM之后,才能开始绘制,对吗?另一种说法是,将
放在
的末尾是最好的做法,这样页面在下载脚本之前呈现一些内容


我的问题是,解析DOM树是什么时候发生的,我们怎样才能说它完成了呢?在我的理解中,
最终也是DOM树的一部分,只有在加载的脚本中我们才能调用DOM树。浏览器从上到下读取html文件,创建DOM树,当它看到
时,它停止下载并执行它,直到解析完成整个页面。或者,页面是否在解析DOM树的同时绘制页面?

这实际上取决于浏览器加载所有内容的具体顺序,但对于DOM解析,它是自上而下工作的。解析器一个分支一个分支地移动,因此当它遇到头部时,它将通过每个子级移动。如果一个元素有一个子元素,它将在返回树之前移动到子元素上。要将其放在非常基本的伪代码中:

while DOM != parsed:
    if current_node.has_child():
        current_node = child_node
        execute_node()
    elif current_node.has_sibling():
        current_node = sibling_node
        execute_node()
    elif current_node.has_parent_sibling():
        current_node = parent_sibling
        execute_node()
    else:
        current_node = parent_node
它本质上处理作为父节点的脚本/链接标记,如果是外部文件,则启动HTTP/S GET请求,并在转到下一个节点之前解析代码。因此,我们在末尾使用put脚本标记的原因是,它们通常不在页面加载时使用,而是在页面加载后处理事情。所以大家的共识是,最好先在页面上找到一些东西,然后稍后再加载JS,这样它就可以处理菜单项上非常重要的动画

当然也有例外,您可以指定DOM解析器异步执行脚本——解析器创建一个额外的线程来解析JS——或者发出延迟GET请求,但在HTML文档解析完成之前不会解析文件

另一种说法是,将
放在
的末尾是最好的做法,这样页面在下载脚本之前呈现一些内容

将脚本标记放在body标记末尾的主要原因是:downloadexecuteJavaScripts将阻止HTML解析(或者,您可以说它们只是解析的一部分)。如果将它们放在
中,用户可能会等待很长时间才能在网页上看到任何内容。图像您的html页面如下所示:

<html>
  <head>
    <!-- this huge.js takes 10 seconds to download -->
    <script src="huge.js"></script>
  </head>
  <body>
    <div>
      My most fancy div!
    </div>
  </body>
</html>

// huge.js
(function () {
   // Some CPU intensive JS operations which take 10 second to complete
})();

我最喜欢的潜水艇!
//巨大的
(功能(){
//一些CPU密集型JS操作需要10秒才能完成
})();
浏览器在到达
标记后将立即开始执行那些CPU密集型JS。它将阻止解析其余HTML内容。因此,在这种情况下,用户在下载并执行JavaScript之前(总共需要20秒)将无法看到他的花式div

您可以使用
DOMContentLoaded
检测是否加载和解析初始DOM。最后一段中的陈述非常正确:每次HTML解析器看到
,它都会同步下载并执行它(请参见注意2)。在执行所有
并解析所有HTML之后,将触发
DOMContentLoaded

注意1
DOMContentLoaded
不会等待CSS和图像

注意2:大多数浏览器都有“推测性解析”功能。如果有多个JavaScript文件,将同时下载它们。但是,它们仍将由主线程按顺序执行

关于你的最后一个问题:

或者,页面是否在解析DOM树的同时绘制页面

根据我自己的理解,答案是,浏览器将尽快尝试绘制。也就是说,绘制引擎不会等待渲染树完全就绪。所以应该有一条分开的线来处理油漆

如果我的理解有任何错误,请随时纠正我:)

参考资料:


  • TL;DR:解析在收到文档后立即开始

    解析与绘画 要获得更详细的解释,我们需要深入了解渲染引擎的工作方式

    呈现引擎解析HTML文档并创建两棵树:
    内容树
    呈现树
    。内容树包含所有DOM节点。呈现树包含所有样式信息(CSSOM
    CSSOM
    ),仅包含呈现te页面所需的DOM节点

    一旦创建了渲染树,浏览器就会经历两个过程:应用
    布局
    绘制
    每个DOM节点。应用布局意味着计算DOM节点应该出现在屏幕上的确切坐标。绘画意味着实际渲染像素并应用风格属性

    这是一个循序渐进的过程:浏览器不会等到所有HTML都被解析。部分内容将被解析和显示,而过程将继续处理来自网络的其余内容

    您可以在浏览器中看到此过程。例如,打开Chrome开发者工具并加载您选择的站点

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

    记录时间线可以让你更深入地了解引擎盖下发生的事情。我将上面的屏幕截图作为一个例子,表明在解析文档时会进行绘制。注意,initia
    // Results in an unbalanced tree
    <script>document.write("<div>");</script>
    
    // Results in an unfinished token
    <script>document.write("<div></div");</script>