script的src必须为URL而非本地路径;正确用相对或以/开头的绝对路径,并通过HTTP服务访问;async下载完立即执行,defer等DOM构建完按序执行;type缺省可能被当module处理;404仅警告不报错,需查Network面板。
script 标签的 src 属性必须是绝对或相对 URL,不能是本地文件路径(如 C:\xxx.js)
浏览器出于安全限制,直接用 file:// 协议打开 html 时,src 值写成 c:\project\script.js 或 /c:/project/script.js 都会失败,控制台报 net::err_file_not_found 或跨域错误。
正确做法只有两种:
- 用相对路径,比如
script.js、js/main.js、../lib/utils.js—— 路径基于当前 HTML 文件位置解析 - 用绝对路径,但必须以
/开头(表示站点根目录),例如/assets/js/app.js;注意这不是文件系统根目录,而是你起的本地服务器(如http://localhost:5000/)的根 - 开发阶段别双击 HTML 打开,用
python3 -m http.server、npx serve或 VS Code Live Server 插件启一个本地 HTTP 服务
async 和 defer 的行为差异直接影响执行时机和 DOM 可用性
不加这两个属性时,<script src="a.js"></script> 是同步阻塞加载:下载 + 解析 + 执行完才继续解析后续 HTML,容易卡住页面渲染。
选哪个取决于脚本用途:
-
async:适合完全独立的脚本(如统计代码、广告 SDK),下载时不阻塞 HTML 解析,但**下载完立刻执行**,不保证顺序,也不等 DOM 就绪 —— 所以不能在它里面直接操作document.getElementById -
defer:适合依赖 DOM 的初始化逻辑(如表单验证、菜单挂载),下载不阻塞解析,但**等到整个 HTML 解析完、DOM 构建完成后再按顺序执行** —— 这是最接近“放在</body>前”的效果 - 两者都只对带
src的外部脚本生效;内联脚本(<script>...</script>)不支持这两个属性
type 属性不是可有可无的,默认值已变,旧写法可能出兼容问题
过去常写 <script type="text/javascript">,但现在 HTML5 规范中,type="module" 和 type="application/json" 等新类型出现,type 缺省时浏览器默认按 type="module" 处理 —— 仅当没有 type 且没有 src 时,才回退到传统脚本。
立即学习“Java免费学习笔记(深入)”;
稳妥写法:
- 普通外部脚本:显式写
<script type="text/javascript" src="app.js"></script>或直接省略type(现代浏览器仍兼容) - ES Module 脚本:必须写
<script type="module" src="main.mjs"></script>,此时自动启用defer行为,且不支持document.write - 避免混用:不要在一个页面里既有
type="module"又有传统脚本还依赖全局变量,模块作用域隔离,window.foo不会自动暴露
404 错误不会中断页面,但 script 加载失败后没有任何提示
<script src="missing.js"></script> 加载 404 时,HTML 继续渲染,控制台只有一条浅色警告(Chrome 中是「Failed to load resource」),没报错,也没回调通知 —— 很多开发者因此以为脚本“运行了”,实际根本没进。
排查建议:
- 打开浏览器开发者工具的 Network 标签页,过滤
JS,看对应请求状态码是不是 404 或 403 - 检查路径是否拼错,尤其注意大小写(Linux/macOS 服务器区分大小写,
Script.js≠script.js) - 如果用构建工具(如 Webpack/Vite),确认输出目录结构和
public资源是否被正确拷贝,src值是否按实际部署路径配置
外部 JS 是否加载成功,靠肉眼基本看不出来。得养成先盯 Network 面板再查控制台的习惯。











