为什么我的JavaScript仅在script标签加defer属性时才能正常运行?
问题原因分析
不加defer时JS无法运行的逻辑
浏览器解析HTML的默认规则是从上到下依次执行,当解析到<head>里没有加任何特殊属性的<script>标签时,会暂停后续HTML的解析工作,优先下载这个JS文件并立即执行,等JS执行完成后才会继续解析<body>里的内容。
你的JS代码开头就调用了document.getElementById("btn")和document.querySelector(".color")去获取DOM元素,但此时浏览器还没解析到<body>里的按钮和span标签,DOM树中根本不存在这两个节点,所以你拿到的btn和color变量都是null,给null绑定点击事件会直接抛出错误,整个功能自然无法运行。
加defer后正常运行的逻辑
defer是HTML给script标签提供的异步加载属性,它的作用是:
- 浏览器碰到带
defer的script标签时,不会阻塞HTML的解析,会在后台异步下载JS文件 - 等到整个HTML全部解析完成、DOM树完全构建好之后,才会执行带defer的JS代码
这时候你要获取的按钮、span元素都已经被解析到DOM树里了,能正常拿到对应的节点,绑定点击事件的逻辑不会报错,功能自然可以正常运行。
其他可替代的解决方案
除了加defer之外,你也可以用下面两种常用方式解决同类问题:
- 把
<script>标签放到</body>结束标签的前面,这样解析到JS的时候,body里的所有元素都已经加载完成 - 把所有JS逻辑包裹在
DOMContentLoaded事件回调里,等DOM加载完成后再执行代码,示例如下:
document.addEventListener('DOMContentLoaded', function() { // 把你原来的所有JS代码放到这里面即可 const colors = ["green", "red", "rgba(133,122,200)", "#f15025"]; const btn = document.getElementById("btn"); const color = document.querySelector(".color"); btn.addEventListener("click", function () { const randomNumber = 2; document.body.style.backgroundColor = colors[randomNumber]; color.textContent = colors[randomNumber]; }); })
内容的提问来源于stack exchange,提问作者Ali Bayraktar
相关产品推荐
相关产品推荐

