【问题标题】:Browsers react differently to <script> inside <body>浏览器对 <body> 中的 <script> 的反应不同
【发布时间】:2026-01-21 17:15:02
【问题描述】:

这是我无法理解的问题。看这段JS代码:

<!DOCTYPE HTML>
<html>

<head>
  <meta charset="utf-8">
</head>

<body>
  <p>The Beginning...</p>
  <script>
    alert('Hello, Wolrd!');
  </script>
  <p>...The End Of Doc</p>
</body>

</html>

所以问题是我不明白为什么The Beginning 段落在&lt;script&gt; 标记之前没有加载/可见。在几乎所有教程中,都解释了浏览器在遇到脚本之前加载所有 HTML,然后当遇到脚本时,浏览器开始以脚本的编译模式工作,然后当脚本结束时,浏览器返回 HTML 模式。

但实际上它的行为似乎有所不同,因为 The Beginning 文本仅出现在 脚本警报之后:

请有人解释一下为什么会这样?


PS:只有 Firefox 的行为如教程中所述。

【问题讨论】:

  • 这是因为alert,如果您输入console.log,它将按预期运行。
  • @AnshumanJaiswal 我不确定这是解决此问题的正确方法,因为 console.log 不会停止脚本的运行,但 alert 会 - 这里使用 alert 的主要原因是停止脚本并查看停止时加载了什么:)
  • 有趣的是,正如您所说,您所描述的内容与很多教程相矛盾,并且投票率很高,like this one。我可以在 Chrome 和 Safari 中重现该行为,但不能在 Firefox 上重现。我还找到了this question,和你的很相似。在那个问题中,大多数用户无法重现 OP 的行为,但这是我在 Safari 和 Chrome 上遇到的行为。
  • 这似乎和当前的问题有些关系:developers.google.com/web/updates/2017/03/dialogs-policy
  • 奇怪的是,&lt;script defer&gt; 没有任何改变。

标签: javascript html


【解决方案1】:

脚本之前的元素已创建并添加到 DOM,但浏览器在@987654321 之前没有机会渲染它们(更新页面显示以显示它们) @ 使整个 UI 线程戛然而止。浏览器需要创建元素并将它们添加到DOM; 不需要渲染它们。有些会,有些不会。两者都不是“错误的”。

我们可以很容易地通过寻找它甚至阅读它的文本来证明第一段的存在:

<p>The Beginning...</p>
<script>
  alert("Hello, World! First paragraph's text: " + document.querySelector("p").textContent);
</script>
<p>...The End Of Doc</p>

【讨论】:

    【解决方案2】:

    它必须按照教程所说的那样运行;所以我认为这是浏览器的弱点,根据以下情况:

    我们有this CodePen(您在评论中链接),代码如下:

    <p id="one">
        The Beginning...</p>
    <script>
        alert(document.getElementById('one').innerHTML);
    </script>
    <p id="two">...The End Of Doc</p>
    

    场景 1:

    点击链接并等待代码加载。如您所说,警报会弹出,但未显示The BeginningThe End。关闭警报后,文本可见。

    场景 2(目前仅在 Chrome 中发生。Safari 的行为类似于场景 1):

    在新选项卡中打开链接而不关注它(您可以使用Ctrl + Right ClickMouse Wheel Click)。等待大约 10 秒(您会在 CodePen 的 favIcon 中看到一个小蓝点)。现在打开 CodePen 选项卡和 BOOM!您将看到 alertThe Beginning/The End 文本。

    这让我觉得 Chrome 无法正常工作。

    【讨论】:

    • 这很有趣......但是,它没有回答 OP 的问题:为什么 Chrome 和 Safari 都不显示第一个 &lt;p&gt; 元素?此外,值得一提的是,CodePen 中的“蓝点行为”仅发生在 Chrome 中,而不是 Safari。
    • @GerardoFurtado 我想说根据他们应该的标准,但他们不会导致这是一个错误。这种情况表明它是实施中的一个弱点。
    • @GerardoFurtado 关于“蓝点行为”,看起来在 safari 中动态更改图标是不可能的(或者几乎不可能以不同于 chrome 的方式)。
    • @GerardoFurtado 哦,我现在明白了,所以场景 2 只发生在 chrome 而不是 safari 中,我会更新答案。感谢提及。
    • @AhmadMaleki - 这是很有趣的行为(显示“The End”部分),但alert 是一件有趣且不合时宜的事情。请注意,即使在场景 2 中,警报仍然具有正确的内容:codepen.io/anon/pen/JZNbZq 如果您使用可能影响页面其余部分呈现的内容,请注意差异:codepen.io/anon/pen/LrybvY 我认为您没有给 Chrome开发人员在 2018 年真正思考如何以智能方式处理这些 90 年代的遗留问题。:-)
    【解决方案3】:

    因为 JavaScript 在 DOM 完成解析之前立即执行(这是 ready 解决的“问题”)。 你可以包含一个事件监听器来检查你的 DOM 是否准备好了

    <script>
    var callback = function() {
        alert( 'Hello, Wolrd!' );
    };
    
    if(document.readyState === "complete" || (document.readyState !== "loading" && !document.documentElement.doScroll)) {
        callback();
    } else {
        document.addEventListener("DOMContentLoaded", callback);
    }
    </script>
    

    但您可以做的最简单的事情是将您的&lt;script&gt; 标记移到&lt;/body&gt; 之前的末尾。

    <!DOCTYPE HTML>
    <html>
    
    <head>
      <meta charset="utf-8">
    </head>
    
    <body>
    
      <p>The Beginning...</p>
    
    
      <p>...The End Of Doc</p>
    
      <script>
        alert( 'Hello, Wolrd!' );
      </script>
    </body>
    
    </html>
    

    【讨论】:

    • 顺便说一句!似乎在 DOM 内部,脚本之前的这些元素已经存在,这里是示例 codepen.io/tonkhao/pen/bKBLQm - 所以这只是可见性问题
    • 您在脚本末尾放置脚本的下面示例确实不会改变这种情况 - 无论如何,正文中的 html 标记仅在警报完成后才会出现 - 所以看起来在哪里并不重要脚本放在正文中 - 无论如何浏览器都会先完成 te 脚本,然后是正文中的 html
    最近更新 更多