JS异步加载的三种方式

一:同步加载

我们平时使用的最多的一种方式。

同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止后续的解析,只有当当前加载完成,才能进行下一步操作。所以默认同步执行才是安全的。但这样如果 js 中有输出 document 内容、修改 dom、重定向等行为,就会造成页面堵塞。所以一般建议把标签放在结尾处,这样尽可能减少页面阻塞。


二:异步加载

异步加载又叫非阻塞加载,浏览器在下载执行 js 的同时,还会继续进行后续页面的处理。主要有三种方式。

方法一:也叫 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); })();

属性是 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 Eval、 Script In Iframe、 Script defer 属性、 document.write(script tag)。

XHR Injection(XHR 注入):通过 XMLHttpRequest 来获取 javascript,然后创建一个 script 元素插入到 DOM 结构中。ajax 请求成功后设置 script.text 为请求成功后返回的 responseText。

 //获取 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 的执行方式不同,直接把 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 Irame:在父窗口插入一个 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("



            
            
                

评论
  目录