<script>应放在</body>前以避免阻塞HTML解析和渲染;依赖DOM的脚本必须确保执行时机晚于DOM加载,不依赖的可放<head>但需加defer;async适合完全独立脚本;src与内联不可混用;type="module"默认defer且启用ES模块语义;跨域脚本需加crossorigin并配服务端CORS头。

script 标签放哪?head 里还是 body 结尾?
绝大多数情况下,<script> 应该放在 </body> 前——不是为了“习惯”,而是避免阻塞 HTML 解析和页面渲染。浏览器遇到 <script src="..."></script> 时会暂停 DOM 构建,去下载、解析、执行脚本,期间用户看到的是白屏或不完整页面。
常见错误现象:Uncaught TypeError: Cannot read property 'xxx' of null,本质是脚本试图操作还没加载出来的 DOM 元素。
- 如果脚本不依赖 DOM(比如只定义工具函数、上报逻辑),可放
<head>,但必须加defer - 如果脚本依赖 DOM(比如
document.getElementById),必须确保执行时机晚于 DOM 加载,推荐放</body>前 - 用
async适合完全独立的脚本(如统计代码),但它不保证执行顺序,也不等 DOM
src 和内联脚本混用?别这么干
<script src="a.js">console.log('hi');</script> 这种写法无效:只要用了 src 属性,标签内的所有内容都会被忽略。
使用场景很明确:要么外链,要么内联,不能同时存在。
立即学习“前端免费学习笔记(深入)”;
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
- 想调试时快速加点逻辑?删掉
src,把代码写进标签体;上线前再拆出去 - 某些构建工具(如 Vite)支持
import内联模块,但那是 ES 模块语法,和传统<script>不是一回事 - 内联脚本没有缓存优势,体积稍大就应外链
type="module" 和普通 script 的关键区别
加了 type="module" 的 <script> 默认就是 defer 行为,且启用 ES 模块语义:顶层 this 是 undefined,必须显式 export/import,不自动共享全局变量。
容易踩的坑:Uncaught SyntaxError: Cannot use import statement outside a module —— 这说明你写了 import 却没加 type="module",或者服务器没返回正确的 Content-Type: text/javascript(注意:模块脚本对 MIME 类型敏感)。
- 模块脚本天然支持
await顶层语法,普通脚本不支持 - 模块路径必须是相对或绝对 URL,
import './util.js'不能省略后缀,也不能写成import 'util' - 旧版 Safari 和 IE 完全不支持
type="module",需检查兼容性或用构建工具降级
跨域脚本怎么加 crossorigin?什么时候必须加?
当脚本来自不同源(比如 CDN 上的 https://cdn.example.com/lib.js),又想捕获它的运行时错误(比如 window.onerror 或 try/catch),就必须加 crossorigin 属性,否则错误堆栈会被屏蔽为 Script error.。
但光加 crossorigin 不够,CDN 服务器还必须返回 Access-Control-Allow-Origin 响应头,否则浏览器直接拒绝加载。
-
crossorigin="anonymous":不带凭据(cookies),最常用 -
crossorigin="use-credentials":带 cookies,需服务端额外配置Access-Control-Allow-Credentials: true - 漏掉
crossorigin导致错误无法定位,尤其在监控系统里很隐蔽


















