浏览器在解析 HTML 的时候,如果遇到一个没有任何属性的script标签,就会暂停解析,先发送网络请求获取该 JS 脚本的代码内容,然后让 JS 引擎执行该代码,当代码执行完毕后恢复解析。它不会等待后续加载的文档元素,读取到就会开始加载和执行,这样就阻塞了后续文档的加载。
script 阻塞了浏览器对 HTML 的解析,如果获取 JS 脚本的网络请求迟迟得不到响应,或者 JS 脚本执行时间过长,都会导致白屏,用户看不到页面内容。
而 defer 和 async属性都是去异步加载外部的JS脚本文件,它们都不会阻塞页面的解析,其区别如下:
1、 执行顺序:
- 多个带async属性的标签,不能保证加载的顺序,完全依赖于网络传输结果,谁先到执行谁;
- 多个带defer属性的标签,按照在 HTML 中出现的顺序执行;
2、 脚本是否并行执行:
- async:后续文档的加载和执行 与 js脚本的加载 是并行进行的,即异步执行;
- defer:加载后续文档的过程 和 js脚本的加载 (仅加载不执行)是并行进行的(异步),js脚本需要等到文档所有元素解析完成之后才执行,DOMContentLoaded事件触发执行之前。
3、是否阻塞解析html
- async:可能阻塞,也可能不阻塞
- defer: 不阻塞
async阻塞的场景:当浏览器遇到带有 async 属性的 script 时,请求该脚本的网络请求是异步的,不会阻塞浏览器解析 HTML,一旦网络请求回来之后,如果此时 HTML 还没有解析完,浏览器会暂停解析,先让 JS 引擎执行代码,执行完毕后再进行解析。
async不阻塞的场景:如果在 JS 脚本请求回来之前,HTML 已经解析完毕了,立即执行 JS 代码,不存在阻塞问题
defer不阻塞的原因:获取该脚本的网络请求是异步的,不会阻塞浏览器解析 HTML,一旦网络请求回来之后,如果此时 HTML 还没有解析完,浏览器不会暂停解析并执行 JS 代码,而是等待 HTML 解析完毕再执行 JS 代码
avaScript脚本延迟加载的方式有哪些?
延迟加载就是等页面加载完成之后再加载 JavaScript 文件。 js 延迟加载有助于提高页面加载速度。
- defer 属性:
- async 属性:
- 动态创建 DOM 方式:动态创建 DOM 标签的方式,可以对文档的加载事件进行监听,当文档加载完成后再动态的创建 script 标签来引入 js 脚本。
- 使用 setTimeout 延迟方法:设置一个定时器来延迟加载js脚本文件
- 让 JS 最后加载:将 js 脚本放在文档的底部,来使 js 脚本尽可能的在最后来加载执行。