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

那么,哪里是放置<script>标记的正确位置?

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


如果您使用的是jQuery,那么将JavaScript代码放在您认为最好的地方,并使用$(document).ready()确保在执行任何函数之前正确加载。

附带说明:我喜欢<head>部分中的所有脚本标记,因为这似乎是最干净的地方。


就在结束正文标记之前,如在底部放置脚本所述:

将脚本放在底部脚本造成的问题是它们阻止并行下载。HTTP/1.1规范建议浏览器每个主机名并行下载的组件不超过两个。如果您从多个主机名提供图像,您可以同时获得两次以上的下载。然而,当下载脚本时,浏览器不会启动任何其他下载,即使是在不同的主机名上。


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

出于各种原因,有人持不同意见,首先是有意识地开始执行页面加载事件。


事实证明,它无处不在。

您可以使用类似jQuery的方法来延迟执行,这样它放在哪里就不重要了(除了解析过程中的小性能影响)。


根据脚本及其用法,最好的方法(在页面加载和渲染时间方面)可能不是使用常规的<script>-标记本身,而是动态地异步触发脚本加载。

有一些不同的技术,但最直接的方法是在触发window.onload事件时使用document.createElement(“script”)。然后,当页面本身已呈现时,首先加载脚本,从而不会影响用户等待页面出现的时间。

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

有关更多信息,请参阅SteveSouders(YSlow的创建者,现供职于谷歌)撰写的耦合异步脚本。


雅虎推广的标准建议!卓越性能团队,将<script>标记放在文档的<body>元素的末尾,这样它们就不会阻止页面的呈现。

但有一些新的方法可以提供更好的性能,正如我在另一个关于Google Analytics JavaScript文件加载时间的回答中所描述的:

Steve Souders(客户端性能专家)的一些精彩幻灯片介绍了:并行加载外部JavaScript文件的不同技术它们对加载时间和页面呈现的影响浏览器显示什么样的“正在进行”指示符(例如状态栏中的“加载”、沙漏鼠标光标)。


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

或者最好的做法(如果这不是问题)是,你可以制作一个模态加载框,将JavaScript代码放在页面底部,并在加载脚本的最后一行时使其消失。这样可以避免用户在加载脚本之前在页面中使用操作。也要避免不正确的造型。


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

获取HTML页面(例如index.HTML)开始分析HTML解析器遇到引用外部脚本文件的<script>标记。浏览器请求脚本文件。同时,解析器阻止并停止解析页面上的其他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在下载并执行文档之前不会修改文档,所以解析器停止解析。

过时的建议

解决这个问题的旧方法是将<script>标记放在<body>的底部,因为这样可以确保解析器直到最后都不会被阻塞。

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

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

现代方法

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

异步的

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

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

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

推迟

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

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

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

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

结论

当前最先进的技术是将脚本放在<head>标记中,并使用异步或延迟属性。这允许您的脚本尽快下载,而不会阻止您的浏览器。

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

工具书类

异步与延迟属性通过延迟和异步有效地加载JavaScript删除渲染阻止JavaScript异步、延迟、模块:一个可视化的Cheatsheet


非阻塞脚本标记可以放置在任何位置:

<script src="script.js" async></script>
<script src="script.js" defer></script>
<script src="script.js" async defer></script>

异步脚本一旦可用,将立即异步执行当文档完成解析时执行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
-->

尽管如此,异步脚本提供了以下优点:

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

使用支持回调的外部脚本可以避免执行顺序问题。许多第三方JavaScript API现在支持非阻塞执行。下面是一个异步加载GoogleMapsAPI的示例。


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

如果将脚本放在<body>的末尾,则所有DOM都有机会加载和渲染(页面将更快地“显示”)<script>将可以访问所有这些DOM元素。

另一方面,将其放置在<body>start或更高位置之后将执行脚本(其中仍然没有任何DOM元素)。

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


如果您仍然非常关心Internet Explorer版本10之前的支持和性能,那么最好始终将脚本标记设置为HTML正文的最后一个标记。这样,您就可以确定DOM的其余部分已经加载,并且不会阻塞和渲染。如果您不太关心版本10之前的Internet Explorer,您可能希望将脚本放在文档的开头,并使用defer来确保它们仅在加载DOM后运行(<script type=“text/javascript”src=“path/to/script1.js”defer></script>)。如果您仍然希望代码在版本10之前的Internet Explorer中运行,请不要忘记将代码包装在窗口中!


    <script src="myjs.js"></script>
</body>

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

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

如果需要,请选中此项:

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


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

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

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


您可以将大多数<script>引用放在<body>的末尾。

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


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

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

如果您在jQuery中编写,以下内容可以在头文档中,并且将在文档加载后执行:

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

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

在头中包含脚本可以很早加载脚本,并且可以在加载整个网页之前使用。

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


现代方法是使用ES6“模块”类型脚本。

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

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

进一步阅读:

脚本和模块之间的区别与脚本相比,模块的执行被延迟(默认情况下模块被延迟)ES6模块的浏览器支持


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

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

但现代浏览器还支持其他一些最佳方式,如异步和延迟加载外部JavaScript文件。

异步和延迟

通常HTML页面的执行是逐行开始的。当遇到外部JavaScript<script>元素时,HTML解析将停止,直到下载JavaScript并准备好执行。可以使用defer和async属性更改正常的页面执行。

推迟

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

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

异步

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

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

何时使用哪些属性

如果您的脚本独立于其他脚本并且是模块化的,请使用异步。如果使用异步加载script1和script2,则两者都将运行与HTML解析并行,一旦下载并且可用。如果您的脚本依赖于另一个脚本,则对这两个脚本都使用defer:当script1和script2以延迟的顺序加载时,然后,script2将在script1完全执行后执行。如果script2依赖于script1,则必须执行此操作。如果您的脚本足够小并且依赖于另一个脚本然后使用不带属性的脚本,并将其置于所有异步脚本之上。

参考:外部JavaScript JS文件–优点、缺点、语法、属性


您可以通过使用围绕JavaScript代码的专用HTML标记<script>在HTML文档中添加JavaScript代码。

<script>标记可以放在HTML的<head>部分、<body>部分或</body>close标记之后,具体取决于何时加载JavaScript。

通常,JavaScript代码可以放在文档<head>部分的内部,以便将它们包含在HTML文档的主要内容之外。

但是,如果您的脚本需要在页面布局中的某一点运行(例如使用document.write生成内容时),则应该将其放在应该调用的位置,通常在<body>部分。


通常,我们必须在结束体标记之前放置脚本,以期待某些特定场景。

例如:

`<html> <body> <script> document.getElementById("demo").innerHTML = "Hello JavaScript!"; </script> </body> </html>`

最好将其放在</body>结束标记之前。

为什么?根据官方文件:https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics#a_hello_world!_实例

注:说明(上面)放置元素的原因HTML文件的底部附近是浏览器在在文件中显示的顺序。如果JavaScript首先加载,并且它应该会影响HTML尚未加载,可能会出现问题。放置JavaScript靠近HTML页面底部是一种适应这种情况的方法附属国。要了解有关替代方法的更多信息,请参见脚本加载策略。