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

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

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


当前回答

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

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

其他回答

事实证明,它无处不在。

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

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

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

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

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

以下是当浏览器加载带有<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

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

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

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

例如:

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