js延迟加载的几种方法(性能优化defer、async)
这是一个面试经常问到的问题:js的延迟加载方法 (js的延迟加载有助于提高页面的加载速度)主要考察对程序的性能方面是否有研究,程序的性能是一个项目不断地追求的,通常也是项目完成后需要长期做的一件事情,像腾讯QQ依然对程序的性能不断地做优化,让用户的体验更好,性能优化的核心思想就是快,可以预先准备数据(如缓存的使用),可以按需获取,可以分段获取等都是常见的优化手段。解题思路 :1.def...
这是一个面试经常问到的问题:js的延迟加载方法 (js的延迟加载有助于提高页面的加载速度)
主要考察对程序的性能方面是否有研究,程序的性能是一个项目不断地追求的,通常也是项目完成后需要长期做的一件事情,像腾讯QQ依然对程序的性能不断地做优化,让用户的体验更好,性能优化的核心思想就是快,可以预先准备数据(如缓存的使用),可以按需获取,可以分段获取等都是常见的优化手段。
解题思路 :
如果没有defer或async属性,浏览器会立即加载并执行相应的脚本。它不会等待后续加载的文档元素,读取到就会开始加载和执行,这样就阻塞了后续文档的加载。
下图可以直观的看出三者之间的区别:
其中蓝色代表js脚本网络加载时间,红色代表js脚本执行时间,绿色代表html解析。
defer 和 async 属性都是去异步加载外部的JS脚本文件,它们都不会阻塞页面的解析,其区别如下:
1. 执行顺序:多个带async属性的标签,不能保证加载的顺序;多个带defer属性的标签,按照加载顺序执行;
2. 脚本是否并行执行:async属性,表示后续文档的加载和执行与js脚本的加载和执行是并行进行的,即异步执行,将在onload 事件之前完成;defer属性,加载后续文档的加载和js脚本的加载(此时仅加载不执行)是并行进行的(异步),js脚本需要等到文档所有元素解析完成之后才执行,DOMContentLoaded事件触发执行之前;
注:defer或async 只适用于外部脚本文件
1.defer属性
<script src="file.js" defer> </script>
浏览器会并行下载 file.js和其它有 defer 属性的script,而不会阻塞页面后续处理。defer属性在IE 4.0中就实现了,超过10多年了!Firefox从 3.5 开始支持defer属性 。
浏览器会异步的下载该文件并且不会影响到后续DOM
的渲染,并行进行(异步);
defer
脚本会被延迟到整个页面都解析完毕之后再执行,DOMContentLoaded
事件调用前执行。
文档解析时,遇到设置了defer
的脚本,就会在后台进行下载,但是并不会阻止文档的渲染,当页面解析&渲染完毕后,会等到所有的defer
脚本加载完毕并按照顺序执行,执行完毕后会触发DOMContentLoaded
事件。
注:HTML5规范要求脚本按照它们出现的先后顺序执行。在现实当中,延迟脚本并不一定会按照顺序执行。
2.async属性
<script src="file.js" async> </script>
async属性是HTML5新增的。作用和defer类似 加载和渲染后面元素过程将和script的加载和执行并行进行(异步),但是它将在加载完成后立即执行,不能保证脚本会按顺序执行。它们将在onload 事件之前完成。
async
脚本会在加载完毕后执行。
Firefox3.6、Opera 10.5、IE 9和 最新的Chrome 和 Safari 都支持 async 属性。可以同时使用 async 和 defer,这样IE 4之后的所有IE 都支持异步加载。
注释:有多种执行外部脚本的方法:
- 如果 async="async":脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本加载完将被执行)
- 如果不使用 async 且 defer="defer":脚本将在页面完成解析后执行
- 如果既不使用 async 也不使用 defer:在浏览器继续解析页面之前,立即读取并执行脚本会阻断页面的解析
defer和async推荐的应用场景
defer
如果你的脚本代码依赖于页面中的DOM
元素(文档是否解析完毕),或者被其他脚本文件依赖。
例:
- 评论框
- 代码语法高亮
polyfill.js
async
如果你的脚本并不关心页面中的DOM
元素(文档是否解析完毕),并且也不会产生其他脚本需要的数据。
例:
- 百度统计
如果不太能确定的话,用defer
总是会比async
稳定。。。
3.动态创建DOM方式 (使用的最多)-事件监听
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "defer.js";
document.body.appendChild(element);
}
if (window.addEventListener) //添加监听事件
window.addEventListener("load",downloadJSAtOnload, false); //事件在冒泡阶段执行
else if (window.attachEvent)
window.attachEvent("onload",downloadJSAtOnload);
else
window.onload = downloadJSAtOnload;
</script>
PS: 这里插一句 addEventListener() 也是常考的知识点之一:
addEventListener() 方法用于向指定元素添加事件句柄。
使用 removeEventListener() 方法来移除 addEventListener() 方法添加的事件句柄。
语法:element.addEventListener(event, function, useCapture)
event (必须)字符串,指定事件名。注意: 不要使用 “on” 前缀。 例如,使用 “click” ,而不是使用 “onclick”。
function (必须)指定要事件触发时执行的函数。当事件对象会作为第一个参数传入函数。 事件对象的类型取决于特定的事件。例如, “click” 事件属于 MouseEvent(鼠标事件) 对象。
useCapture (可选)布尔值,指定事件是否在捕获或冒泡阶段执行。【true:事件句柄在捕获阶段执行; false:默认,事件句柄在冒泡阶段执行】
<p>该实例使用 addEventListener() 方法来向按钮添加点击事件。</p>
<button id="myBtn">点我</button>
<p id="demo"></p>
<script>
document.getElementById("myBtn").addEventListener("click", function(){
document.getElementById("demo").innerHTML = "Hello World";
});
</script>
效果如图:
4.使用Jquery的getScript()方法
$.getScript("outer.js",function(){//回调函数,成功获取文件后执行的函数
console.log("脚本加载完成")
});
从源码可以看出,这个方法最后还是调用了jQuery.ajax()
来请求了js文件的。
5.使用setTimeout延迟方法的加载时间
延迟加载js代码,给网页加载留出时间
<script type="text/javascript">
function A(){
$.post("/lord/login",{name:username,pwd:password},function(){
alert("Hello World!");
})
}
$(function (){
setTimeout("A()",1000); //延迟1秒
})
</script>
6.让js最后加载
例如引入外部js脚本文件时,如果放入html的head中,则页面加载前该js脚本就会被加载入页面,而放入body中,则会按照页面从上倒下的加载顺序来运行javascript的代码~~~ 所以我们可以把js外部引入的文件放到页面底部,来让js最后引入,从而加快页面加载速度。
上述方法5,6也会偶尔让你收到Google页面速度测试工具的“延迟加载javascript”警告。所以这里的解决方案将是来自Google帮助页面的推荐方案。
//这些代码应被放置在</body>标签前(接近HTML文件底部) <script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "defer.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>
这段代码意思是等到整个文档加载完后,再加载外部文件“defer.js”。
使用此段代码的步骤:
复制上面代码
粘贴代码到HTML的标签前 (靠近HTML文件底部)
修改“defer.js”为你的外部JS文件名
确保你文件路径是正确的。例如:如果你仅输入“defer.js”,那么“defer.js”文件一定与HTML文件在同一文件夹下。
注意:这段代码直到文档加载完才会加载指定的外部js文件。因此,不应该把那些页面正常加载需要依赖的javascript代码放在这里。而应该将JavaScript代码分成两组。一组是因页面需要而立即加载的javascript代码,另外一组是在页面加载后进行操作的javascript代码(例如添加click事件或其他东西)。这些需等到页面加载后再执行的JavaScript代码,应放在一个外部文件,然后再引进来。
若有不足请多多指教!希望给您带来帮助!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)