我应该把<脚本>放在哪里?HTML 标记中的标签?

问题描述:

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

When embedding JavaScript in an HTML document, where is the proper place to put the <script> tags and included JavaScript? I seem to recall that you are not supposed to place these in the <head> section, but placing at the beginning of the <body> section is bad, too, since the JavaScript will have to be parsed before the page is rendered completely (or something like that). This seems to leave the end of the <body> section as a logical place for <script> tags.

那么,在哪里是放置 标签的正确位置?

So, where is the right place to put the <script> tags?

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

(This question references this question, in which it was suggested that JavaScript function calls should be moved from <a> tags to <script> tags. I'm specifically using jQuery, but more general answers are also appropriate.)

当浏览器加载带有 标签的网站时,会发生以下情况:

Here's what happens when a browser loads a website with a <script> tag on it:

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

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

Step #4 causes a bad user experience. Your website basically stops loading until you've downloaded all scripts. If there's one thing that users hate it's waiting for a website to load.

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

Any script can insert its own HTML via document.write() or other DOM manipulations. This implies that the parser has to wait until the script has been downloaded and executed before it can safely parse the rest of the document. After all, the script could have inserted its own HTML in the document.

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

However, most JavaScript developers no longer manipulate the DOM while the document is loading. Instead, they wait until the document has been loaded before modifying it. For example:

<!-- 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:

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 在下载和执行之前不会修改文档,所以解析器停止解析.

Because your browser does not know my-script.js isn't going to modify the document until it has been downloaded and executed, the parser stops parsing.

解决这个问题的旧方法是将 标签放在 的底部,因为这样可以确保解析器不会一直堵到最后.

The old approach to solving this problem was to put <script> tags at the bottom of your <body>, because this ensures the parser isn't blocked until the very end.

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

This approach has its own problem: the browser cannot start downloading the scripts until the entire document is parsed. For larger websites with large scripts and stylesheets, being able to download the script as soon as possible is very important for performance. If your website doesn't load within 2 seconds, people will go to another website.

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

In an optimal solution, the browser would start downloading your scripts as soon as possible, while at the same time parsing the rest of your document.

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

Today, browsers support the async and defer attributes on scripts. These attributes tell the browser it's safe to continue parsing while the scripts are being downloaded.

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

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

Scripts with the async attribute are executed asynchronously. This means the script is executed as soon as it's downloaded, without blocking the browser in the meantime. This implies that it's possible to script 2 is downloaded and executed before script 1.

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

According to http://caniuse.com/#feat=script-async, 97.78% of all browsers support this.

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

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

Scripts with the defer attribute are executed in order (i.e. first script 1, then script 2). This also does not block the browser.

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

Unlike async scripts, defer scripts are only executed after the entire document has been loaded.

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

According to http://caniuse.com/#feat=script-defer, 97.79% of all browsers support this. 98.06% support it at least partially.

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

An important note on browser compatibility: in some circumstances, Internet Explorer 9 and earlier may execute deferred scripts out of order. If you need to support those browsers, please read this first!

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

当前最先进的技术是将脚本放在 标签中并使用 asyncdefer属性.这允许您尽快下载您的脚本,而不会阻止您的浏览器.

The current state-of-the-art is to put scripts in the <head> tag and use the async or defer attributes. This allows your scripts to be downloaded ASAP without blocking your browser.

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

The good thing is that your website should still load correctly on the 2% of browsers that do not support these attributes while speeding up the other 98%.