为什么HTML中script的src写在头部时脚本失效,放body末尾就正常?
问题原因
浏览器加载HTML文档时遵循从上到下逐行解析的规则:
- 当你把script放在head/body开头时,浏览器会先加载并立即执行doggos.js,此时body内的
#tryIt按钮和#demo段落还没有被解析到DOM树中 - 执行
document.getElementById('tryIt')会返回null,后续调用addEventListener会直接抛出JS错误,导致整个脚本逻辑中断,自然点击按钮没有反应 - 脚本放在body闭合标签前时,所有DOM元素已经解析完成,能正常获取到元素绑定事件,所以逻辑正常。
你之前了解的「script放在头部不会完全无法运行」是正确的,这个结论的前提是脚本本身不依赖页面中后续渲染的DOM元素,比如全局工具类、不操作DOM的统计脚本等放在头部是可以正常执行的。
放在head中也能正常运行的解决方案
如果需要把script放在头部,可选择以下任意一种方案:
- 给script标签添加
defer属性
修改head中的script标签为:
带<script src="doggos.js" defer></script>defer标识的脚本会异步加载,等整个HTML文档解析完成后才按顺序执行,不会阻塞DOM渲染,也能保证获取到所有页面元素。 - 把JS逻辑包裹在
DOMContentLoaded事件回调中
修改doggos.js的代码如下:document.addEventListener('DOMContentLoaded', function () { document.getElementById('tryIt').addEventListener('click', function () { document.getElementById('demo').innerHTML = 'Hello World'; }); })DOMContentLoaded事件会在DOM树完全构建完成后触发,绑定在这个事件内的逻辑只有等DOM就绪后才会执行,不受script放置位置影响。 - (不适用于此场景)给script标签添加
async属性async也会让脚本异步加载,但加载完成后会立即执行,不保证执行时机,只有当脚本完全不依赖DOM、也不依赖其他脚本时才适用。
内容的提问来源于stack exchange,提问作者Sun23
相关产品推荐
相关产品推荐

