js的加载、解析和执行会阻塞页面的渲染过程,因此我们希望js脚本能够尽可能的延迟加载,提高页面的渲染速度。
一般有以下几种方式:
1. 动态创建script标签
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
document.head.appendChild(script);
或者可以封装一个
// 手动封装异步加载js的方法
function asyncLoadScript (url, callback) {
var script = document.createElement('script');
script.type = 'text/javascript';
if (script.readyState) {//readyState是IE中的状态码
script.onreadystatechange = function () {
//绑定监听状态码的事件,IE状态码变成complete或者loaded,表示该元素加载完
if (script.readyState == "complete" || script.readyState == "loaded") {
callback();//回调函数,当script加载完后调用
}
}
} else {
//非IE 用onload事件,表示当script加载完时
script.onload = function () {
callback();//回调函数,当script加载完后调用
}
}
script.src = url;//放在这,是为了避免IE立即加载完,立即加载完就不再触发onreadystatechange
document.head.appendChild(script);//加载到页面中去
}
//执行
asyncLoadScript('./js/tools.js', function () {
//code
console.log('按照加载完了:' + url + '文件')
});
2. 设置defer属性
<script defer="defer" src="xxx.js"></script>
或者
<script defer="defer">
//code
</script>
3. 设置async属性
<script async="async" src="xxx.js"></script>
defer与async区别:
①. async,加载和渲染后续文档元素的过程将和 xxx.js 的加载与执行异步
②. defer,加载后续文档元素的过程将和 xxx.js 的加载异步,但是 xxx.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成
defer 与 DOMContentLoaded
如果 script 标签中包含 defer,那么这一块脚本将不会影响 HTML 文档的解析,而是等到 HTML 解析完成后才会执行。而 DOMContentLoaded 只有在 defer 脚本执行结束后才会被触发。 所以这意味着什么呢?HTML 文档解析不受影响,等 DOM 构建完成之后 defer 脚本执行,但脚本执行之前需要等待 CSSOM 构建完成。在 DOM、CSSOM 构建完毕,defer 脚本执行完成之后,DOMContentLoaded 事件触发。
async 与 DOMContentLoaded
如果 script 标签中包含 async,则 HTML 文档构建不受影响,解析完毕后,DOMContentLoaded 触发,而不需要等待 async 脚本执行、样式表加载等等。