js异步加载解决方案
默认情况js是同步加载的,在页面解析的过程中,遇到script外部链接(没有设置async、defer属性)js会阻塞,然后去加载js中的代码并执行,只有当前脚本加载执行完成后,才会继续去解析后面的内容。如果js标签放置头部并且文件过大会导致加载时间过长,页面有较大的空白期,影响用户体验。
- 设置defer属性
<script defer src='index.js'> </script>
defter表示延迟,在解析过程中遇到带有 defer 属性的 script 时,不会阻塞浏览器解析 HTML,在js加载完成之后,如果此时 HTML 还没有解析完,浏览器不会暂停解析并执行 js代码,而是等待 HTML 解析完毕再顺序执行每个设置defer属性中的代码.。
- 设置async属性
<script async src="index.js" ></script>
async 表示异步 , 在当解析的过程中遇到带有async属性的script时,不会阻塞浏览器解析HTML,一旦在js加载完成之后,此时如果HTML还没有解析完成,浏览器会暂停解析,让js引擎去执行加载回来的代码,执行完毕后再继续解析后面内容,这样属性就有些弊端,如果当加载完成后的代码中有获取某一个dom元素并且页面没有解析完成时,有可能获取不到该元素。若有多个async的时候,加载速度不同,谁先加载完谁先执行,如果先加载完成执代码中有依赖于其他文件中的代码,该代码执行也会出现错误。
- 手动实现异步加载
function loadScript(src, callback) {
//创建script标签
var script = document.createElement('script')
//判断script是否加载完成
script.onload = function () {
//当script加载完成时调用函数
callback()
}
//兼容ie
script.onreadystatechange = function () {
if (script.readyState == 'loaded' || script.readyState == 'complete') {
callback()
}
}
//设置script的src路径,在绑定监听状态后面设置,避免加载过快,状态监听不到
script.src = src
//将script元素插入到dom中
document.body.appendChild(script)
}
//调用函数,利用回调执行要执行的函数
loadScript('./js/index.js', function () {
test()
})
创建script节点对象设置其的src属性,监听其的状态,插入到dom中,当js加载完成后在执行回调执行要执行的代码。实现异步加载,也不会造成执行顺序的问题。