我应该在哪里将<script>标记放在HTML标记中?

mip*_*adi 1392 html javascript jquery

在JavaScript文档中嵌入JavaScript时,放置<script>标记和包含JavaScript 的适当位置在哪里?我似乎记得你不应该把它们放在这个<head>部分中,但放在该部分的开头<body>也是不好的,因为在完全呈现页面之前必须解析JavaScript(或类似的东西).这似乎将该部分的末尾<body>作为<script>标记的逻辑位置.

所以,在这里把正确的地方<script>标记?

(这个问题引用了这个问题,其中建议JavaScript函数调用应该从<a>标签移动到<script>标签.我专门使用jQuery,但更一般的答案也是合适的.)

Bar*_*art 1742

以下是浏览器加载带有<script>标记的网站时发生的情况:

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

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

为什么会发生这种情况?

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

然而,大多数JavaScript开发人员不再操作DOM 文档加载.相反,它们会等到文档加载后再修改它.例如:

<!-- index.html -->
<html>
    <head>
        <title>My Page</title>
        <script type="text/javascript" src="my-script.js"></script>
    </head>
    <body>
        <div id="user-greeting">Welcome back, user</div>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

使用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";
});
Run Code Online (Sandbox Code Playgroud)

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

过时的推荐

解决此问题的旧方法是将<script>标记放在您的底部<body>,因为这样可以确保解析器在最终之前不会被阻塞.

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

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

现代的方法

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

异步

<script type="text/javascript" src="path/to/script1.js" async></script>
<script type="text/javascript" src="path/to/script2.js" async></script>
Run Code Online (Sandbox Code Playgroud)

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

根据http://caniuse.com/#feat=script-async,94.57%的浏览器支持此功能.

延缓

<script type="text/javascript" src="path/to/script1.js" defer></script>
<script type="text/javascript" src="path/to/script2.js" defer></script>
Run Code Online (Sandbox Code Playgroud)

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

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

根据http://caniuse.com/#feat=script-defer,94.59%的浏览器支持此功能.94.92%至少部分支持它.

关于浏览器兼容性的重要说明:在某些情况下,IE <= 9可能无序执行延迟脚本.如果您需要支持这些浏览器,请先阅读此内容!

结论

当前最先进的技术是将脚本放在<head>标记中并使用asyncdefer属性.这样可以在不阻止浏览器的情况下尽快下载脚本.

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

  • 我很惊讶没有人引用谷歌的解释...... https://developers.google.com/speed/docs/insights/BlockingJS (59认同)
  • 为什么没有使用`async`和`defer`属性?我的意思是,我从互联网上查看了很多HTML资源,而且我没有在任何地方看到`async`和`defer`属性.......? (34认同)
  • 这个答案有误导性.现代浏览器在到达可能影响HTML的同步脚本标记时不会停止解析,它们只是停止呈现/执行,并继续乐观地解析以开始下载其他资源,如果没有HTML受到影响,可能会随后请求这些资源. (23认同)
  • @Doug例如`document.write`在dom上运行.问题不是*如果*脚本操纵dom,而**当*它操作.只要所有dom操作在'domready`事件触发后发生,你就可以了.jQuery是一个库,因此不会 - 或者不应该 - 自己操纵dom. (7认同)
  • 我不清楚什么触及DOM,什么不是.你能澄清一下吗?在像jquery.js这样的东西上进行异步加载是否安全? (6认同)
  • 这篇文章现在已经3岁了.我猜浏览器支持现在应该超过90%? (3认同)
  • 这个答案也是反对的,[在脚本标签上使用`type`属性被认为是浪费](https://google.github.io/styleguide/htmlcssguide.html#type_Attributes).他们不需要,只是迂腐 (3认同)

Cam*_*mel 232

就在关闭身体标签之前,如上所述

http://developer.yahoo.com/performance/rules.html#js_bottom

把脚本放在底部

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

  • 如果这是最佳实践,为什么堆栈溢出包括<head>中的所有脚本标记?:-P (44认同)
  • 在某些情况下,特别是在ajax重型站点,装载头部实际上可以加快加载时间.请参阅:http://encosia.com/dont-let-jquerys-document-ready-slow-you-down/(请注意,"live()"函数在jquery中已弃用,但该文章仍适用于"on" ()"或"委托"功能).也可能需要加载<head>以保证正确的行为,如@Hermant所指出的那样.最后,http://modernizr.com/docs/建议将其脚本放在<head>中,原因在其网站上有解释. (10认同)
  • @Hermant旧评论,但您可以默认禁用字段,然后在DOM完全加载时使用JS启用它们.这就是Facebook现在似乎在做什么. (9认同)
  • 同意这个概念及其解释.但是如果用户开始玩页面会发生什么.假设我有一个AJAX下拉列表,它会在页面向用户显示后开始加载,但在加载时,用户会点击它!如果"真正不耐烦"的用户提交表单怎么办? (7认同)
  • 警告:不,这是更好的做法。将其放在带有“defer”属性的“&lt;head&gt;”标记内,或者更好地使您的脚本为“type='module'”。现在已经是 2022 年了。 (4认同)
  • 刚用chrome测试过,检查一下是否还是一样.它是.您可以在此处检查浏览器的页面加载时间差异.http://stevesouders.com/cuzillion/ (2认同)
  • 从内容仅来自 HTML 的时代起,这个建议就已经过时了。页面开头太复杂,无法做出如此笼统的陈述。如果您的页面不需要为初始渲染执行任何代码,并且它不会阻止基本交互性,那么它现在仍然有效。但是,如果您使用的是像 vue 这样没有任何服务器端渲染的东西,那么将您的基本脚本放在最后会优先于所有图像和 CSS,使其加载和运行比应有的时间晚得多。 (2认同)

Sal*_*n A 70

非阻塞脚本标记可以放在任何地方:

<script src="script.js" async></script>
<script src="script.js" defer></script>
<script src="script.js" async defer></script>
Run Code Online (Sandbox Code Playgroud)
  • async 脚本一旦可用就会异步执行
  • defer 文档完成解析后执行脚本
  • async defer 如果不支持async,脚本将回退到延迟行为

这样的脚本将在文档就绪后异步执行,这意味着你不能这样做:

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

或这个:

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

或这个:

<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
-->
Run Code Online (Sandbox Code Playgroud)

或这个:

<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
-->
Run Code Online (Sandbox Code Playgroud)

话虽如此,异步脚本提供了以下优势:

  • 并行下载资源:
    浏览器可以并行下载样式表,图像和其他脚本,而无需等待脚本下载和执行.
  • 源顺序独立性:
    您可以将脚本放在头部或主体内而不必担心阻塞(如果您使用的是CMS,则非常有用).执行顺序仍然很重要.

可以通过使用支持回调的外部脚本来规避执行顺序问题.许多第三方JavaScript API现在支持非阻塞执行.以下是异步加载Google Maps API的示例.

  • @elbow 99%的时间``script src = jquery.js>`后面跟着`$(function(){...})`块在页面的某个地方.异步加载并不能保证在浏览器尝试解析这些块时会加载jQuery,因此它会引发_ $未定义错误(如果从缓存加载jQuery,则可能无法获得错误).我回答了一个关于异步加载jQuery并保留`$(function(){...})`的问题.我会看看我是否能找到它,或者你可以看看这个问题:http://stackoverflow.com/q/14811471/87015 (3认同)
  • 这是今天的正确答案 - 使用这种方法意味着更容易保持小部件自包含,不需要花哨的`<head>`包含逻辑. (2认同)

ori*_*rip 37

雅虎推出的标准建议!卓越的性能团队,是将<script>标签放在文档主体的末尾,这样它们就不会阻止页面的呈现.

但是有一些较新的方法可以提供更好的性能,如本回答中所述,关于Google AnalyticsJavaScript文件的加载时间:

有一些伟大的幻灯片由史蒂夫Souders的(客户端性能专家)约:

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


And*_*are 23

如果您正在使用JQuery,那么将javascript放在最适合的地方,并使用它$(document).ready()来确保在执行任何函数之前正确加载内容.

旁注:我喜欢该<head>部分中的所有脚本标签,因为这似乎是最干净的地方.

  • 在头上......呃?`<报头>`? (14认同)
  • 请注意,使用`$(document).ready()`并不意味着您可以将JavaScript*放在任何地方*您仍然需要将它放在`<script src =".../jquery.min之后. js">`你包含jQuery,所以`$`存在. (7认同)
  • 将脚本标记放在<head>部分中并不是最佳选择 - 这会延迟显示页面的可见部分,直到加载脚本为止. (2认同)

All*_*nde 10

XHTML不会验证脚本是否在head元素之外的任何位置. 原来它可以无处不在.

您可以使用jQuery之类的命令来延迟执行,因此放置它的位置并不重要(除了解析期间的小性能命中).


Ama*_*mar 10

<script src="myjs.js"></script>
</body>
Run Code Online (Sandbox Code Playgroud)

脚本标记应始终在正文关闭之前使用或在HTML文件中使用底部.

然后你可以在加载js文件之前先看到页面的内容.

如果需要,请检查:http: //stevesouders.com/hpws/rule-js-bottom.php

  • 这实际上回答了这个问题.我想知道几乎所有发布的例子都没有给出"页面结尾"的正确视觉背景 (2认同)
  • 这个答案非常具有误导性,而且很可能是错误的。[Google](https://developers.google.com/speed/docs/insights/BlockingJS) 和 [MDN](https://developer.mozilla.org/en-US/docs/Web/Events) 中的文章/DOMContentLoaded) 表明同步 JS(这里就是这种情况)总是阻止 DOM 构建和解析,这将导致延迟的首次渲染。因此,无论您将 JS 文件放在 HTML 文档中的哪个位置,只要它是同步的,您就无法看到页面的内容,直到 JS 文件被获取并完成执行 (2认同)

cqu*_*zel 10

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

<script type="module" src="..."></script>
Run Code Online (Sandbox Code Playgroud)

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

此处描述了脚本和模块之间的区别:

/sf/answers/3767503981/

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

https://developers.google.com/web/fundamentals/primers/modules#defer

支持如下所示:

https://caniuse.com/#feat=es6-module

  • 请注意,如果您只是在没有服务器的本地文件系统上尝试一些东西,那么这将不起作用。至少在 Chrome 上,尝试从 HTML 加载 js 时会出现跨域错误,即使它们具有相同的源(文件系统)。 (2认同)

Har*_*hil 10

放置<script>tag</body>最佳位置是在关闭tag之前,因此下载和执行它不会阻止浏览器解析文档中的 html,

加载js文件外有它自己的优势,喜欢它会被浏览器缓存,可以加快页面加载时间,它分离了HTML和JavaScript代码,并帮助更好地管理代码库

但现代浏览器还支持一些其他的最佳方式一样async,并defer加载外部javascript文件。

异步和延迟

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

Defer

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

<script src="/local-js-path/myScript.js" defer></script>
Run Code Online (Sandbox Code Playgroud)

Async

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

<script src="/local-js-path/myScript.js" async></script>
Run Code Online (Sandbox Code Playgroud)

何时使用哪些属性

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

参考资料:knowledgehills.com


dkr*_*etz 6

传统(并且被广泛接受)的答案是"在底部",因为在任何事情开始执行之前,整个DOM都将被加载.

出于各种原因,有异议者从可用的练习开始,故意开始使用页面onload事件执行.


ahm*_*mzl 5

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

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


归档时间:

查看次数:

530427 次

最近记录:

5 年,11 月 前