外部脚本正常执行需确保script标签位置、加载方式和路径正确;放前最稳妥,放需加defer或async;路径错误致404,模块脚本需带扩展名且不共享全局作用域。

外部脚本能正常执行,前提是 <script></script> 标签位置、加载方式和路径都对;错一个,就白写。
script 标签放哪儿才不会报 ReferenceError
浏览器是顺序解析 HTML 的。如果 <script></script> 放在 里又没加 defer 或 async,它会立刻下载并执行——此时 DOM 还没生成,你写的 document.getElementById('btn') 肯定找不到元素。
- 最稳妥:把
<script src="xxx.js"></script>放在前面 - 想放
?必须加defer(按顺序执行,等 DOM 解析完)或async(不保证顺序,适合独立逻辑如统计脚本) - 别用
document.write()动态插入<script></script>—— 它会清空整个页面,现代项目基本等于自毁
src 路径写错的典型表现和排查方法
控制台报 404 Not Found 或 Failed to load resource 是路径问题最直接的信号。不是“文件不存在”,而是“浏览器找错了地方”。
- 相对路径以当前 HTML 文件为基准,不是以 JS 文件、也不是以服务器根目录:比如
index.html在/pages/下,src="js/main.js"就要去找/pages/js/main.js - 想从根目录开始?用
src="/js/main.js"(开头带/),但注意:开发时用本地文件协议(file://)会失效,只适用于 HTTP(S) 服务 - 路径中大小写敏感:Windows 上可能不报错,Linux 服务器上直接 404
加载失败时怎么知道?用 onerror 和 onload 监听
默认情况下,脚本加载失败静默失败,连控制台都不报错(除非网络层拦截)。你不主动监听,根本不知道它根本没进来。
立即学习“前端免费学习笔记(深入)”;
- 给
<script></script>加onerror="console.error('script load failed')",至少能确认是否卡在网络或路径 - 配合
onload可做依赖检查:比如lodash.js加载完再初始化业务代码,避免ReferenceError: _ is not defined - 注意:
onerror不会捕获脚本内部运行时错误(比如undefined.xxx()),那得靠window.onerror或try/catch
模块化场景下 type="module" 的行为差异
加了 type="module",<script></script> 就不再是传统脚本:它默认 defer、自动启用严格模式、支持 import/export,但也会带来兼容性与路径限制。
- 模块内
import的路径必须带扩展名(import {foo} from './utils.js'),不能省略.js - 模块脚本不共享全局作用域:你在
main.js(模块)里声明的var x = 1,不会挂到window.x上 - 本地开发时,Chrome 对
file://协议下的模块加载有限制(CORS),必须起一个本地服务(比如npx serve)
真正容易被忽略的,是路径解析规则和模块加载时机这两层隐式约定——它们不报错,但会让脚本“看起来加载了,实际没执行”。调试时先看 Network 面板里那个 JS 文件是不是 200,再看 Console 有没有 onerror 触发,比反复改代码快得多。











