HTML中script标签应放置的位置

HTML中script标签应放置的位置

技术背景

在浏览器加载包含 <script> 标签的网站时,会按特定顺序执行操作。通常是先获取HTML页面,开始解析HTML,当解析器遇到引用外部脚本文件的 <script> 标签(无 deferasync 属性且非 typemodule 的情况),浏览器会请求该脚本文件,同时解析器会阻塞并停止解析页面上的其他HTML,直到脚本下载并执行完成后,才会继续解析剩余的HTML文档。这种机制会导致用户体验不佳,因为在所有脚本下载完成前,网站基本处于停止加载状态。

实现步骤

传统放置方式

早期解决上述问题的方法是将 <script> 标签放在 <body> 的底部,这样能确保解析器直到最后才被阻塞。示例如下:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
</head>
<body>
<div id="user-greeting">Welcome back, user</div>
<script src="my-script.js"></script>
</body>
</html>
HTML

但这种方式存在问题,浏览器要等到整个文档解析完成后才能开始下载脚本,对于有大量脚本和样式表的大型网站,尽早下载脚本对性能至关重要。

现代放置方式

如今,浏览器支持在脚本上使用 asyncdefer 属性,这些属性告知浏览器在下载脚本时可以安全地继续解析文档。

async属性

使用 async 属性的脚本会异步执行,即脚本下载完成后立即执行,不会阻塞浏览器。示例如下:

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

不过,使用 async 属性无法保证脚本的执行顺序,可能会出现 script2script1 之前下载并执行的情况。

defer属性

使用 defer 属性的脚本会按顺序执行,且不会阻塞浏览器。与 async 脚本不同,defer 脚本只有在整个文档加载完成后才会执行。示例如下:

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

module类型

包含 type="module" 的脚本将被视为JavaScript模块,并像 defer 脚本一样加载。示例如下:

1
<script type="module" src="path/to/srcipt-module.js"></script>
HTML

核心代码

传统方式代码示例

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>传统方式示例</title>
</head>
<body>
<div id="content">这是页面内容</div>
<script src="script.js"></script>
</body>
</html>
HTML

async属性代码示例

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<title>async属性示例</title>
<script src="script1.js" async></script>
<script src="script2.js" async></script>
</head>
<body>
<div id="content">这是页面内容</div>
</body>
</html>
HTML

defer属性代码示例

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<title>defer属性示例</title>
<script src="script1.js" defer></script>
<script src="script2.js" defer></script>
</head>
<body>
<div id="content">这是页面内容</div>
</body>
</html>
HTML

module类型代码示例

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>module类型示例</title>
<script type="module" src="module-script.js"></script>
</head>
<body>
<div id="content">这是页面内容</div>
</body>
</html>
HTML

最佳实践

目前的最佳实践是将脚本放在 <head> 标签中,并使用 asyncdefer 属性,这样可以让脚本尽快下载,同时不阻塞浏览器。这样即使在不支持这些属性的2%的浏览器上,网站也能正常加载,而在其他98%的浏览器上可以加快加载速度。

常见问题

传统方式的问题

<script> 标签放在 <body> 底部时,浏览器要等到整个文档解析完成后才能开始下载脚本,对于大型网站可能会影响性能。

async属性的问题

使用 async 属性无法保证脚本的执行顺序,可能会导致依赖关系出错。例如:

1
2
<script src="jquery.js" async></script>
<script>jQuery(something);</script>
HTML

可能会抛出 jQuery is not defined 错误。

defer属性的问题

虽然 defer 属性可以保证脚本按顺序执行,但如果脚本依赖于页面加载过程中的某些操作,可能会出现问题。

兼容性问题

部分旧版本浏览器可能不支持 asyncdefer 属性,需要考虑兼容性处理。


HTML中script标签应放置的位置
https://119291.xyz/posts/html-script-tags-placement/
作者
ww
发布于
2025年5月26日
许可协议