我应该将 <script> 标签放在 HTML 标记中的啥位置?

Posted

技术标签:

【中文标题】我应该将 <script> 标签放在 HTML 标记中的啥位置?【英文标题】:Where should I put <script> tags in HTML markup?我应该将 <script> 标签放在 HTML 标记中的什么位置? 【发布时间】:2010-09-30 23:41:44 【问题描述】:

html 文档中嵌入 javascript 时,放置 &lt;script&gt; 标记和包含 JavaScript 的合适位置在哪里?我似乎记得您不应该将它们放在&lt;head&gt; 部分中,但是放在&lt;body&gt; 部分的开头也很糟糕,因为必须在页面完全呈现之前解析JavaScript(或类似的东西)。这似乎将&lt;body&gt; 部分的end 留作&lt;script&gt; 标签的逻辑位置。

那么,放置&lt;script&gt;标签的正确位置吗?

(这个问题引用this question,其中建议将JavaScript函数调用从&lt;a&gt;标签移动到&lt;script&gt;标签。我专门使用jQuery,但更一般的答案也是合适的。)

【问题讨论】:

如果您也只是在寻找一个简单的解决方案,并且您正在使用一些服务器端生成器,例如 Jekyll,我建议您将脚本包含在其中。简单多了! 如果来自寻找这个的搜索引擎:许多答案都不清楚“脚本标签”到底应该在哪里。如果 'script' 标签是 after ' 【参考方案1】:

如果您使用 jQuery,请将 JavaScript 代码放在您认为最好的位置,并使用$(document).ready() 确保在执行任何函数之前正确加载内容。

附带说明:我喜欢 &lt;head&gt; 部分中的所有脚本标签,因为那似乎是最干净的地方。

【讨论】:

在头脑中……呃? &lt;header&gt;? 请注意,使用 $(document).ready() 并不意味着您可以将 JavaScript 放在您喜欢的任何地方 - 您仍然必须将它放在包含 jQuery 的 &lt;script src=".../jquery.min.js"&gt; 之后,这样$ 就存在了。 将脚本标签放在 部分不是最佳选择 - 这将延迟页面可见部分的显示,直到脚本加载为止。 不,@Dan,header 元素是 HTML 文档内容的一部分,应该在 body element. The head 中出现一次或多次。文档的数据和非内容数据。现在,deferasync 是脚本标签的理想场所。 header 元素应该只包含描述文档后面部分的信息。 @ProfK,Dan 在 4 年前发布此问题时指的是原始未经编辑的问题。如您所见,该问题在一年后被编辑。【参考方案2】:

就在结束正文标记之前,如 Put Scripts at the Bottom 所述:

将脚本放在底部

脚本导致的问题是它们会阻止并行下载。 HTTP/1.1 规范建议浏览器每个主机名并行下载不超过两个组件。如果您从多个主机名提供图像,则可以同时进行两次以上的下载。但是,在下载脚本时,浏览器不会启动任何其他下载,即使在不同的主机名上也是如此。

【讨论】:

同意这个概念及其解释。但是如果用户开始玩这个页面会发生什么。假设我有一个 AJAX 下拉菜单,它将在页面出现给用户后开始加载,但在加载时,用户点击了它!如果一个“非常不耐烦”的用户提交表单怎么办? @Hermant 旧评论,但您可以在默认情况下禁用这些字段,然后在 DOM 完全加载时使用 JS 启用它们。这就是 Facebook 现在似乎正在做的事情。 刚刚用 chrome 测试了这个,看看是否还是一样。它是。您可以在此处查看浏览器的页面加载时间差异。 stevesouders.com/cuzillion 如果这是最佳实践,为什么堆栈溢出会将其所有脚本标记包含在 中? :-P 在某些情况下,尤其是在 ajax 繁重的网站中,在 head 中加载实际上可以加快加载时间。请参阅:encosia.com/dont-let-jquerys-document-ready-slow-you-down(请注意,“live()”函数在 jquery 中已弃用,但本文仍适用于“on()”或“delegate”函数)。可能还需要加载 以保证@Hermant 指出的正确行为。最后,modernizr.com/docs 建议将其脚本放在 中,原因在其网站上已说明。【参考方案3】:

最保守(并且被广泛接受)的答案是“在结束标记之前的底部”,因为这样整个 DOM 将在任何东西开始执行之前被加载。

出于各种原因,有一些反对者从可用的做法开始,即故意从页面加载事件开始执行。

【讨论】:

Re "at the bottom"":但是before结束body标签(&lt;/body&gt;)?你能说清楚点吗?(但是没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的)。【参考方案4】:

事实证明它可以无处不在。

您可以使用 jQuery 之类的东西来推迟执行,这样它的放置位置就无关紧要了(解析过程中对性能的小影响除外)。

【讨论】:

XHTML 将使用正文中的脚本标签进行验证,包括严格的和过渡的。然而,样式标签可能只在头部。 “放在哪里都无所谓”:但不是所以结果不是well-formed HTML?【参考方案5】:

根据脚本及其使用情况,最好的可能(就页面加载和渲染时间而言)可能是不使用传统的

这自然要求脚本本身不需要渲染页面。

有关详细信息,请参阅 Steve Souders(YSlow 的创建者,但现在在 Google)的帖子 Coupling async scripts

【讨论】:

(不要将 Steve Souders 与 Steve Saunders 或 John Saunders 混淆。)【参考方案6】:

由 Yahoo! 推广的标准建议Exceptional Performance 团队将&lt;script&gt; 标签放在文档正文的末尾,这样它们就不会阻塞页面的呈现。

但有一些更新的方法可以提供更好的性能,如 this answer 关于 Google Analytics JavaScript 文件的加载时间所述:

有一些 great slides Steve Souders(客户端性能专家)关于:

并行加载外部 JavaScript 文件的不同技术 它们对加载时间和页面呈现的影响 浏览器显示什么样的“进行中”指示器(例如状态栏中的“加载”、沙漏鼠标光标)。

【讨论】:

Re“在文档正文的末尾”Before结束正文标签(&lt;/body&gt;) ,大概?你能说得清楚一点吗? (但没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的)。【参考方案7】:

这取决于。如果您加载的脚本是设置页面样式/使用页面中的操作(如单击按钮)所必需的,那么您最好将其放在顶部。如果您的样式是 100% CSS 并且您有按钮操作的所有后备选项,那么您可以将其放在底部。

或者最好的事情(如果这不是问题的话)是您可以制作一个模式加载框,将您的 JavaScript 代码放在页面底部,并在加载脚本的最后一行时使其消失。这样,您可以避免用户在加载脚本之前在您的页面中使用操作。还要避免不恰当的造型。

【讨论】:

Re "将你的 JavaScript 代码放在页面底部":但是 before 结束正文标记( &lt;/body&gt;)?你能说得清楚一点吗? (但没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的)。【参考方案8】:

当浏览器加载带有&lt;script&gt; 标签的网站时会发生以下情况:

    获取 HTML 页面(例如 index.html) 开始解析 HTML 解析器遇到引用外部脚本文件的&lt;script&gt; 标记。 浏览器请求脚本文件。同时,解析器会阻止并停止解析您页面上的其他 HTML。 一段时间后,脚本被下载并随后执行。 解析器继续解析 HTML 文档的其余部分。

第 4 步会导致糟糕的用户体验。在您下载所有脚本之前,您的网站基本上会停止加载。如果用户讨厌一件事,那就是等待网站加载。

为什么会发生这种情况?

任何脚本都可以通过document.write() 或其他 DOM 操作插入自己的 HTML。这意味着解析器必须等到脚本下载并执行后才能安全地解析文档的其余部分。毕竟,脚本可以在文档中插入自己的 HTML。

但是,大多数 JavaScript 开发人员不再在文档加载时操作 DOM。相反,他们会等到文档加载完毕后再进行修改。例如:

<!-- index.html -->
<html>
    <head>
        <title>My Page</title>
        <script src="my-script.js"></script>
    </head>
    <body>
        <div id="user-greeting">Welcome back, user</div>
    </body>
</html>

JavaScript:

// my-script.js
document.addEventListener("DOMContentLoaded", function() 
    // this function runs when the DOM is ready, i.e. when the document has been parsed
    document.getElementById("user-greeting").textContent = "Welcome back, Bart";
);

因为您的浏览器不知道 my-script.js 在文档下载并执行之前不会修改该文档,因此解析器停止解析。

过时的推荐

解决此问题的旧方法是将&lt;script&gt; 标签放在&lt;body&gt; 的底部,因为这样可以确保解析器直到最后都不会被阻塞。

这种方法有其自身的问题:在整个文档被解析之前,浏览器无法开始下载脚本。对于具有大型脚本和样式表的大型网站,能够尽快下载脚本对于性能非常重要。如果您的网站在 2 秒内没有加载,人们会转到另一个网站。

在最佳解决方案中,浏览器会尽快开始下载您的脚本,同时解析文档的其余部分。

现代方法

今天,浏览器支持脚本的asyncdefer 属性。这些属性告诉浏览器在下载脚本时继续解析是安全的。

异步

<script src="path/to/script1.js" async></script>
<script src="path/to/script2.js" async></script>

具有 async 属性的脚本是异步执行的。这意味着脚本在下载后立即执行,同时不会阻塞浏览器。 这意味着可以在脚本 1 之前下载并执行脚本 2。

根据http://caniuse.com/#feat=script-async,97.78% 的浏览器都支持这个。

推迟

<script src="path/to/script1.js" defer></script>
<script src="path/to/script2.js" defer></script>

具有 defer 属性的脚本按顺序执行(即第一个脚本 1,然后是脚本 2)。这也不会阻止浏览器。

与异步脚本不同,延迟脚本仅在整个文档加载完成后执行。

根据http://caniuse.com/#feat=script-defer,97.79% 的浏览器都支持这一点。 98.06% 至少部分支持。

关于浏览器兼容性的重要说明:在某些情况下,Internet Explorer 9 及更早版本可能会乱序执行延迟脚本。如果您需要支持这些浏览器,请先阅读this!

(要了解更多信息并查看异步、延迟和普通脚本之间差异的一些非常有用的可视化表示,请查看此答案参考部分的前两个链接)

结论

当前的最新技术是将脚本放在&lt;head&gt; 标记中并使用asyncdefer 属性。这可以让您的脚本尽快下载,而不会阻止您的浏览器。

好消息是,您的网站仍应在 2% 的不支持这些属性的浏览器上正确加载,同时加快其他 98% 的速度。

参考文献

async vs defer attributes Efficiently load JavaScript with defer and async Remove Render-Blocking JavaScript Async, Defer, Modules: A Visual Cheatsheet

【讨论】:

我很惊讶没有人引用谷歌的解释...developers.google.com/speed/docs/insights/BlockingJS 我不清楚什么涉及 DOM,什么不涉及。你能澄清一下吗?对 jquery.js 之类的东西进行异步加载是否安全? @Doug 例如document.write 对dom进行操作。问题不是 if 脚本操纵 dom,而是 when 它会。只要在domready 事件触发之后发生所有 dom 操作,就可以了。 jQuery 是一个库,因此它不会 - 也不应该 - 自己操作 dom。 这个答案具有误导性。现代浏览器在到达可能影响 HTML 的同步脚本标签时不会停止解析,它们只是停止渲染/执行,并继续乐观地解析以开始下载其他资源,如果不影响 HTML,则后续可能会请求这些资源。跨度> 为什么asyncdefer 属性没有在任何地方使用?我的意思是,我从互联网上查看了很多 HTML 资源,但我在任何地方都没有看到 asyncdefer 属性。 ... ?【参考方案9】:

非阻塞脚本标签几乎可以放置在任何地方:

<script src="script.js" async></script>
<script src="script.js" defer></script>
<script src="script.js" async defer></script>
async 脚本将在可用时立即异步执行 defer 脚本在文档完成解析后执行 async defer 如果不支持异步,脚本将退回到延迟行为

此类脚本将在文档准备好后异步执行,这意味着您不能这样做:

<script src="jquery.js" async></script>
<script>jQuery(something);</script>
<!--
  * might throw "jQuery is not defined" error
  * defer will not work either
-->

或者这个:

<script src="document.write(something).js" async></script>
<!--
  * might issue "cannot write into document from an asynchronous script" warning
  * defer will not work either
-->

或者这个:

<script src="jquery.js" async></script>
<script src="jQuery(something).js" async></script>
<!--
  * might throw "jQuery is not defined" error (no guarantee which script runs first)
  * defer will work in sane browsers
-->

或者这个:

<script src="document.getElementById(header).js" async></script>
<div id="header"></div>
<!--
  * might not locate #header (script could fire before parser looks at the next line)
  * defer will work in sane browsers
-->

话虽如此,异步脚本具有以下优点:

资源并行下载: 浏览器可以并行下载样式表、图像和其他脚本,而无需等待脚本下载和执行。 源顺序独立: 您可以将脚本放在 head 或 body 中,而不必担心阻塞(如果您使用 CMS,则很有用)。但执行顺序仍然很重要。

可以通过使用支持回调的外部脚本来规避执行顺序问题。许多第三方 JavaScript API 现在支持非阻塞执行。这是loading the Google Maps API asynchronously 的示例。

【讨论】:

这是今天的正确答案 - 使用这种方法意味着更容易让您的小部件保持独立,无需花哨的 &lt;head&gt; 包含逻辑。 我很困惑为什么在包含 jQuery 时不能使用 asyncdefer,因为您在第二个块中指定:&lt;script src="jquery.js" async&gt;&lt;/script&gt;。你能解释为什么吗?我认为我需要为性能添加 async 标记——根据公认的答案——所以即使 jQuery 仍在加载我的页面也可以加载]。谢谢! @elbow 99% 的时间,&lt;script src=jquery.js&gt; 后面跟着$(function() ... ) 页面某处的块。异步加载并不能保证在浏览器尝试解析这些块时会加载 jQuery,因此它会引发 $ is not defined 错误(如果 jQuery 是从缓存中加载的,您可能不会收到该错误)。我回答了一个关于异步加载 jQuery 并保留 $(function() ... ) 的问题。我看看能不能找到,或者你可以看看这个问题:***.com/q/14811471/87015 @SalmanA 谢谢!是的,我属于那 99%。我首先需要jquery lib 来加载,然后我剩余的.js 脚本。当我在jquery lib 脚本标签上声明asyncdefer 时,我的.js 脚本不起作用。我认为$(function() ... )protected ——我猜不是。 当前解决方案: 我不会在 jquery lib 脚本中添加 deferasync,但我会在后续 .js 脚本中添加 async。注意:我这样做任何的原因是为了让 Google Page Speed 满意。再次感谢您的帮助!欢迎任何其他建议。 (或指向您之前答案的链接)。 :) @elbow 见***.com/a/21013975/87015,它只会给你一个想法,而不是完整的解决方案。您可以改为搜索“jquery 异步加载器库”。【参考方案10】:

脚本会阻止 DOM 加载,直到它被加载并执行。

如果您将脚本放在&lt;body&gt; 的末尾,则所有 DOM 都有机会加载和呈现(页面将“显示”得更快)。 &lt;script&gt; 将有权访问所有这些 DOM 元素。

另一方面,将它放在&lt;body&gt; 或以上开始之后将执行脚本(其中仍然没有任何 DOM 元素)。

您包含 jQuery,这意味着您可以将其放置在您希望的任何位置并使用 .ready()。

【讨论】:

【参考方案11】:

如果您在 version 10 之前仍然非常关心 Internet Explorer 的支持和性能,最好始终将脚本标记作为 HTML 正文的最后一个标记。这样,您就可以确定 DOM 的其余部分已被加载,并且您不会阻塞和渲染。

如果您在 Internet Explorer 10 之前的版本中不再关心太多,您可能希望将脚本放在文档的头部并使用defer 以确保它们仅在您的 DOM 加载后运行(&lt;script type="text/javascript" src="path/to/script1.js" defer&gt;&lt;/script&gt;)。如果您仍然希望您的代码在 10 版之前的 Internet Explorer 中运行,请不要忘记将您的代码包装在 window.onload 中,尽管如此!

【讨论】:

在接受的答案中,这被称为“过时的推荐”。如果你仍然是认真的,你可能应该提供一些参考来支持它。【参考方案12】:
    <script src="myjs.js"></script>
</body>

脚本标签应始终在body close之前或HTML底部文件中使用。

页面将加载 HTML 和 CSS,稍后将加载 JavaScript。

如果需要,请检查:

http://stevesouders.com/hpws/rule-js-bottom.php

【讨论】:

这实际上回答了这个问题。我想知道几乎所有发布的示例都没有给出“页面结束”的正确视觉上下文 这个答案非常具有误导性,很可能是错误的。 Google 和 MDN 中的文章表明,同步 JS(这里就是这种情况)总是会阻塞 DOM 构造和解析,这将导致延迟首次渲染。因此,在获取 JS 文件并完成执行之前,无论您将 JS 文件放在 HTML 文档中的哪个位置,只要它是同步的,您就无法看到页面的内容 它还引用了 2009 年提出的观点,不再相关。 你的意思是“否则你将能够在加载 js 文件之前看到内容,这很糟糕吗?” 最好不要将脚本标签放在正文或 html 代码的末尾。就像其他声明性或元信息一样,这应该放在头部,以减少到处都是无内容相关信息的混乱。习惯使用异步甚至更好的延迟。不过,Word Press 可能有点棘手。它将 JavaScript 放在 wp_head 中,但没有延迟。 ***.com/questions/18944027/…【参考方案13】:

我认为这取决于网页执行。

如果要显示的页面在不加载 JavaScript 的情况下无法正常显示,则应先包含 JavaScript 文件。

但是,如果您无需下载 JavaScript 文件就可以显示/呈现网页,那么您应该将 JavaScript 代码放在页面底部。因为它会模拟快速页面加载,从用户的角度来看,页面加载速度似乎更快。

【讨论】:

【参考方案14】:

您可以将大部分&lt;script&gt; 引用放在&lt;body&gt; 的末尾。

但是如果您的页面上有使用外部脚本的活动组件,那么它们的依赖项(.js 文件)应该在此之前(最好在 head 标记中)。

【讨论】:

【参考方案15】:

编写 JavaScript 代码的最佳位置是在 &lt;/body&gt; 标记之后或之前的文档末尾,以先加载文档,然后执行 JavaScript 代码。

<script> ... your code here ... </script>
</body>

如果你写jQuery,则可以在头文档中执行以下操作,并在文档加载后执行:

<script>
    $(document).ready(function()
        // Your code here...
    );
</script>

【讨论】:

它抛出SyntaxError 您的回答没有错,但急需更新。 将脚本放在正文或 html 代码的末尾不是一个好主意。通常的做法是将这种元信息放在它所属的位置:头部。 Re"在文档末尾...【参考方案16】:

在末尾包含脚本主要用于首先显示网页的内容/样式的地方。

在头部包含脚本会提前加载脚本,可以在整个网页加载之前使用。

如果最后输入脚本,则只有在加载整个样式和设计后才会进行验证,这对于快速响应的网站来说是不受欢迎的。

【讨论】:

【参考方案17】:

2019 年的现代方法是使用 ES6 模块类型脚本

<script type="module" src="..."></script>

默认情况下,模块是异步加载和延迟加载的。也就是说,您可以将它们放在任何地方,它们将并行加载并在页面加载完成时执行。

这里描述了脚本和模块之间的区别:

Classic scripts vs. module scripts in JavaScript

与脚本相比,模块的执行如下所述:

Modules are deferred by default

此处显示支持:

Can I use... Support tables for HTML5, CSS3, etc

【讨论】:

不错的信息添加到知识库 请注意,如果您只是在没有服务器的本地文件系统上尝试内容,这将不起作用。至少在 Chrome 上,你会在尝试从 HTML 加载 js 时遇到跨域错误,即使它们都具有相同的来源,即你的文件系统。【参考方案18】:

放置&lt;script&gt;标签的最佳位置是在关闭&lt;/body&gt;标签之前,因此下载和执行它不会阻止浏览器解析文档中的HTML,

在外部加载 JavaScript 文件也有它自己的优势,比如它会被浏览器缓存,可以加快页面加载时间,它可以将 HTML 和 JavaScript 代码分开,有助于更好地管理代码库。

但是现代浏览器也支持一些其他的优化方式,比如asyncdefer来加载外部JavaScript文件。

异步和延迟

通常 HTML 页面的执行是逐行开始的。当遇到外部 JavaScript &lt;script&gt; 元素时,会停止 HTML 解析,直到下载 JavaScript 并准备好执行。可以使用deferasync 属性更改此正常页面执行。

Defer

当使用 defer 属性时,JavaScript 会与 HTML 解析并行下载,但只有在完整的 HTML 解析完成后才会执行。

<script src="/local-js-path/myScript.js" defer></script>

Async

使用 async 属性时,只要遇到脚本就会下载 JavaScript,下载后会与 HTML 解析一起异步(并行)执行。

<script src="/local-js-path/myScript.js" async></script>

什么时候使用哪些属性

如果您的脚本独立于其他脚本并且是模块化的,请使用async。 如果您使用 async 加载 script1 和 script2,两者都将运行 与 HTML 解析并行,一旦它们被下载 并且可用。 如果您的脚本依赖于另一个脚本,请同时使用 defer: 当 script1 和 script2 以 defer 的顺序加载时,那么 script1 保证首先执行, 那么 script2 将在 script1 完全执行后执行。 如果 script2 依赖于 script1,则必须这样做。 如果您的脚本足够小并且依赖于另一个脚本 类型为async,然后使用没有属性的脚本并将其置于所有async 脚本之上。

参考:External JavaScript JS File – Advantages, Disadvantages, Syntax, Attributes

【讨论】:

【参考方案19】:

您可以通过使用包裹 JavaScript 代码的专用 HTML 标记 &lt;script&gt; 在 HTML 文档中添加 JavaScript 代码。

&lt;script&gt; 标记可以放置在 HTML 的 &lt;head&gt; 部分、&lt;body&gt; 部分或 &lt;/body&gt; 关闭标记之后,具体取决于您希望 JavaScript 何时加载。

一般来说,JavaScript 代码可以进入文档&lt;head&gt; 部分,以便将它们包含在 HTML 文档的主要内容之外。

但是,如果您的脚本需要在页面布局中的某个位置运行(例如使用document.write 生成内容时),您应该将其放在应该调用它的位置,通常在&lt;body&gt; 部分中.

【讨论】:

Re "在

以上是关于我应该将 <script> 标签放在 HTML 标记中的啥位置?的主要内容,如果未能解决你的问题,请参考以下文章

Script 和 Noscript 标签

JavaScript 02 script标签

HTML中的<style;标签和<script;标签的位置

我可以使用 css 禁用 <script> 标签进行媒体查询吗?

js标签放在html的什么位置比较好

<script> 标签何时应该可见,为啥可以?