内部脚本和外部脚本
向HTML页面中插入JavaScript的主要方法就是使用script
元素,有两种方式
- 内联脚本:直接在页面中嵌入JavaScript代码
<head>
<script>
alert('这是内联脚本!')
</script>
</head>
- 外联脚本:引用外部JavaScript文件
<head>
<script src='someone.js'></script>
</head>
在浏览器加载HTML过程中,HTML 解析器运行于主线程之中,并且在遇到 </script>
标签后会被阻塞,直到脚本从网络中被获取和执行。也就是说<script>
标签中的脚本会阻塞浏览器的渲染,这样也被称为“渲染阻塞”。
解决阻塞的方案
script
标签提供了两个属性:defer和async,作为进行异步加载的解决方案
async
该布尔属性指示浏览器是否在允许的情况下异步执行该脚本。该属性对于内联脚本无作用 (即没有src属性的脚本)。也就是说,async属性告诉浏览器先把文件下载下来,在“时机成熟”的时候再执行。异步脚本一定会在页面的load事件前执行,但可能会在DOMContentLoaded事件触发之前或之后执行。而且更加需要注意的是,标记为async的脚本并不保证按照指定他们的先后顺序执行。所以,确保各个异步脚本互不依赖非常重要。
defer
这个布尔属性被设定用来通知浏览器该脚本将在文档完成解析后,触发 DOMContentLoaded 事件前执行。如果缺少 src 属性(即内嵌脚本),该属性不应被使用,因为这种情况下它不起作用。对动态嵌入的脚本使用 async=false
来达到类似的效果。
区别
从上图可以看到,defer和async都能达到异步加载的目的,他们都告诉浏览器应该立即进行下载,但是下载后的执行时间是不一样的。
- async会在下载完成之后,浏览器空间时就会执行,依然有可能造成渲染阻塞
- 而defer会在HTML所有资源解析结束之后才会执行。
总结
- defer和async都是异步加载外部JS文件
- defer和async的差别在于脚本下载完成之后何时执行,显然defer是更接近需求的
- async不保证脚本的执行顺序
- async在外部JS加载完毕之后,浏览器空闲时触发执行
- defer是在外部JS加载完毕之后,整个文档解析完成后触发执行
- defer更像是将
<script>
标签放在<body>
之后的效果,但是它是异步加载,可以节省时间