脚本位置无唯一标准,关键取决于功能需求:依赖DOM的内联脚本须置于</body>前;defer仅对带src的外部脚本生效;async适用于独立第三方脚本;内联脚本中需转义</script>避免提前闭合。

脚本标签没有“唯一正确位置”,关键看它要做什么、是否依赖 DOM、要不要阻塞渲染。
依赖 DOM 的内联脚本必须放在 </body> 前
比如你写 document.getElementById("app"),但脚本在 <head> 里执行,DOM 根本没生成,结果就是 null。放到底部最直接安全:
<body>
<div id="app"></div>
<script>document.getElementById("app").textContent = "done";</script>
</body>
- 这是最不容易出错的写法,尤其适合快速原型或简单页面
- 注意:不能写成
</body><script>...</script></html>—— 浏览器会自动把它“塞进”<body>,但不符合规范,审查工具可能报 warning - 多个内联脚本按顺序执行,无加载竞争问题
defer 只对带 src 的外部脚本生效
很多人给内联脚本加 defer,比如:<script defer>console.log("hi");</script>,这完全无效 —— 规范明确要求 defer 必须配合 src 属性才起作用。
- 正确用法:
<script defer src="main.js"></script>,它会并行下载、等 DOM 构建完再按顺序执行 - 适合有依赖关系的业务脚本(如
utils.js→app.js) -
type="module"脚本默认带defer行为,不用额外写
async 适合完全独立的第三方脚本
像统计、埋点、广告 SDK 这类脚本,不操作 DOM、不依赖其他 JS、也不被其他 JS 依赖,就该用 async:
立即学习“前端免费学习笔记(深入)”;
- 它下载时不阻塞 HTML 解析,下载完立刻执行,时机不可控
- 典型场景:
<script async src="ga.js"></script>放在<head>里没问题 - 两个
async脚本之间执行顺序不保证,别指望它们串行 - 千万别对主业务逻辑用
async,否则document.querySelector很可能报错
内联脚本里写 </script> 会提前闭合标签
如果你在 <script> 标签里直接写字符串 "</script>",HTML 解析器会在第一个 </script> 处就认为脚本结束了,后面代码全失效。
- 错误写法:
<script>console.log("</script>");</script> - 正确写法之一:
<script>console.log("<\/script>");</script>(斜杠转义) - 或拆开:
<script>console.log("<" + "/script>");</script> - 这个坑只存在于内联脚本,外部文件(
src="xxx.js")里怎么写都行
真正容易被忽略的不是“放 head 还是 body”,而是脚本是否真的需要立即执行、有没有隐式 DOM 依赖、以及 defer 和 async 的语义边界 —— 这些比位置本身更能决定页面是否白屏、交互是否卡顿。



















