JavaScript同步、异步与延迟加载详解
本文详细解析JavaScript的三种加载模式:同步阻塞、异步非阻塞及延迟加载。重点介绍HTML5的async与defer属性用法,以及Script DOM Element、XHR注入、动态创建iframe等异步实现技巧,并探讨通过缓存机制解决JS执行阻塞问题的延迟加载方案,帮助开发者优化页面性能。
本文介绍了JavaScript中同步、异步及延迟加载的具体实现方式,供读者参考学习。
同步加载机制与优化
一、同步加载
这是日常开发中最常见的加载方式。
<script src="http://yourdomain.com/script.js"></script>
同步模式也称为阻塞模式,它会暂停浏览器的后续处理与解析,直到当前脚本加载并执行完毕。虽然默认同步执行能确保顺序安全,但如果脚本中包含document.write输出、DOM修改或重定向等操作,会导致页面渲染堵塞。因此,通常建议将<script>标签放置在<body>标签结束前,以尽量减少对页面初始渲染的阻塞影响。
异步加载的多种实现方式
二、异步加载
异步加载(非阻塞加载)允许浏览器在下载和执行JavaScript的同时,继续解析后续页面内容。主要包含以下三种实现方式。
方法一:Script DOM Element
(function(){
var scriptEle = document.createElement("script");
scriptEle.type = "text/javasctipt";
scriptEle.async = true;
scriptEle.src = "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js";
var x = document.getElementsByTagName("head")[0];
x.insertBefore(scriptEle, x.firstChild);
})();
<async>属性是HTML5新增的异步支持特性,该方法被称为Script DOM Element。Google Analytics和Google+ Badge均采用了这种异步加载代码。
(function(){;
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();
然而,在脚本执行完成前,此方法会阻止onload事件的触发。由于许多页面需要在onload事件中执行额外的渲染工作,这仍可能导致部分页面初始化处理被阻塞。
方法二:在onload事件中异步加载
(function(){
if(window.attachEvent){
window.attachEvent("load", asyncLoad);
}else{
window.addEventListener("load", asyncLoad);
}
var asyncLoad = function(){
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
}
)();
该方法将插入script的逻辑封装在一个函数中,并将其绑定到window的onload事件上执行。这种方式解决了阻塞onload事件触发的问题。
注:需区分DOMContentLoaded与load事件。前者在document解析完成后触发,此时DOM元素可用但图片、视频等资源可能未加载完毕,作用类似于jQuery的ready事件;后者则在页面所有资源(包括图片、视频等)全部加载完毕后触发。
方法三:其他异步加载技巧
利用JavaScript的动态特性,还存在多种异步加载方案:XHR Injection(XHR注入)、XHR Eval、Script In Iframe、Script defer属性以及document.write(script tag)。
XHR Injection(XHR注入):通过XMLHttpRequest获取JavaScript代码,随后创建script元素并插入DOM结构。在ajax请求成功后,将返回的responseText赋值给script.text属性。
//获取XMLHttpRequest对象,考虑兼容性。
var getXmlHttp = function(){
var obj;
if (window.XMLHttpRequest)
obj = new XMLHttpRequest();
else
obj = new ActiveXObject("Microsoft.XMLHTTP");
return obj;
};
//采用Http请求get方式;open()方法的第三个参数表示采用异步(true)还是同步(false)处理
var xmlHttp = getXmlHttp();
xmlHttp.open("GET", "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js", true);
xmlHttp.send();
xmlHttp.onreadystatechange = function(){
if (xmlHttp.readyState == 4 && xmlHttp.status == 200){
var script = document.createElement("script");
script.text = xmlHttp.responseText;
document.getElementsByTagName("head")[0].appendChild(script);
}
}
XHR Eval:与XHR Injection不同,它直接将responseText放入eval()函数中执行。
//获取XMLHttpRequest对象,考虑兼容性。
var getXmlHttp = function(){
var obj;
if (window.XMLHttpRequest)
obj = new XMLHttpRequest();
else
obj = new ActiveXObject("Microsoft.XMLHTTP");
return obj;
};
//采用Http请求get方式;open()方法的第三个参数表示采用异步(true)还是同步(false)处理
var xmlHttp = getXmlHttp();
xmlHttp.open("GET", "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js", true);
xmlHttp.send();
xmlHttp.onreadystatechange = function(){
if (xmlHttp.readyState == 4 && xmlHttp.status == 200){
eval(xmlHttp.responseText);
//alert($);//可以弹出$,表明JS已经加载进来。click事件放在其它出会出问题,应该是还没加载进来
$("#btn1").click(function(){
alert($(this).text());
});
}
}
Script In Iframe:在父窗口中插入一个iframe元素,并在该iframe内部执行JS加载操作。
var insertJS = function(){alert(2)};
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var doc = iframe.contentWindow.document;//获取iframe中的window要用contentWindow属性。
doc.open();
doc.write("<script>var insertJS = function(){};<\/script><body onload='insertJS()'></body>");
doc.close();
GMail Mobile方案:业内将JS内容置于注释中以避免立即执行,在需要时获取script中的text内容并去除注释,随后调用eval()执行。
<script type="text/javascript">
/*
var ...
*/
</script>
HTML5 async与defer属性详解
HTML5新属性:async和defer defer属性:自IE4.0起已存在。defer声明脚本中不包含document.write或DOM修改。浏览器会并行下载其他带有defer属性的script,且不阻塞页面后续处理。注意:所有defer脚本必须保证按顺序执行。
<script type="text/javascript" defer></script>
async属性:HTML5新增属性。脚本将在下载完成后尽快执行,作用与defer类似,但不能保证脚本按顺序执行。它们将在onload事件之前完成。
<script type="text/javascript" defer></script>
Firefox 3.6、Opera 10.5、IE 9以及较新的Chrome和Safari浏览器均支持async属性。同时使用async和defer属性,可使IE 4之后的所有IE版本支持异步加载。
若没有async属性,script将立即获取(下载)并执行,期间会阻塞浏览器的后续处理。若存在async属性,script将被异步下载并执行,同时浏览器继续处理后续内容。
总结:对于支持HTML5的浏览器,实现JS异步加载只需在script元素中添加async属性;为兼容老版本IE,还需添加defer属性。对于不支持HTML5的浏览器(IE可通过defer实现),可采用上述几种方法。其原理主要是在DOM中写入script或通过eval函数执行JS代码,可将其置于匿名函数中执行、在onload中执行、通过XHR注入实现,或创建iframe元素并在其中执行插入JS代码。
延迟加载原理与实现方案
三、延迟加载
部分JS代码仅在特定场景下使用,无需在页面初始化时加载。延迟加载旨在解决此问题,将JS拆分为多个模块,页面初始化时仅加载立即需要的JS,其余JS则延迟至首次使用时再加载,类似于图片的延迟加载策略。
JS加载分为下载和执行两个阶段。异步加载仅解决了下载问题,但代码下载完成后会立即执行,执行期间浏览器处于阻塞状态,无法响应其他需求。
解决思路:为解决JS延迟加载问题,可利用异步加载进行缓存但不立即执行,待需要时再执行。缓存方式是将JS内容作为Image或Object对象加载,从而避免立即执行,并在首次需要时触发执行。
1:模拟较长的下载时间:
利用thread使其sleep一段时间后再执行下载操作。
2:模拟较长的JS代码执行时间
var start = Number(new Date());
while(start + 5000 > Number(new Date())){//执行JS}
这段代码将使JS执行耗时5秒才完成!
JS延迟加载机制(LazyLoad):简而言之,即在浏览器滚动到特定位置时触发相关函数,实现页面元素加载或某些动作执行。如何实现浏览器滚动位置检测?可通过定时器实现,比较某一时刻页面目标节点位置与浏览器滚动条高度,以判断是否需执行函数。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
JS reduce实战:数组去重、扁平化与分组统计
2026-11-05 13:05:36
JS代码怎么在线压缩?新手操作指南与工具推荐
2026-11-04 18:07:25
fflate 与 pako.js 性能对比:JS 解压库怎么选
2026-11-03 22:54:05
JS DOM查询性能优化:缓存引用与减少重排重绘
2026-11-03 22:48:27
在线运行JavaScript代码时的沙箱限制与跨域问题
2026-11-03 22:29:33








