参考: <<高性能JavaScript>> Nicbolas C. Zakas 著
javascript代码的下载和执行过程会阻塞浏览器的其他进程, 比如页面的绘制, 遇到<script>标签的时候都必须停下来等待代码的下载并执行. 然后才继续处理其他部分.
无阻塞加载javascript代码的推荐方式:
1 // 将下面的这段加载代码放到</body>的闭合标签之前,这样确保了JS执行过程中不会阻碍页面的其他 2 // 内容显示, 其次第二个js文件完成下载时, 应用所需要的DOM结构已经创建完成, 并做好了交互的准备, 3 // 从而可以避免检测 winodw.onload事件. (注: loader.js中存放的是loadScript()的实现) 4 <script type="text/javascript" src="loader.js"></script> 5 <script type="text/javascript"> 6 loadScript("the-rest.js",function(){ 7 app.init(); 8 }); 9 </script>
也可以将loadScript 直接嵌入页面, 从而避免多产生一次HTTP请求
1 function loadScript(url,callback){ 2 var script = document.createElement("script"); 3 script.type = "text/javascript"; 4 if(script.readyState){//for IE 5 script.onreadystatechange = function(){ 6 if(script.readyState == "onload" || 7 script.readyState == "complete"){ 8 script.onreadystatechange = null; //删除事件处理器, 避免重复调用,IE自身的问题 9 callback(); 10 } 11 } 12 }else{ // for other browser,<script>标签的onload事件. 13 script.onload = function(){ 14 callback(); 15 }; 16 } 17 script.src = url; 18 document.getElementByTagName("head")[0].appendChild(script); 19 }
如果需要按照顺序下载js文件,可以这样调用loadScript. 更好的方式是按顺序放到一个文件中, 避免多次HTTP请求.
1 // load in order, but better way is write all script in one file in order. 2 loadScript("file1.js",function(){ 3 loadScript("file2.js",function(){ 4 loadScript("file3.js",function(){ 5 console.log("All files are loaded in order!"); 6 }); 7 }); 8 });
其他无阻塞模式:
1. 使用defer: 很多浏览器目前不支持(包括chrome)
----- 当一个带有defer属性的js文件下载时, 不会阻塞浏览器的其他进程; 无论是内嵌的还是外联的defer的js脚本, 在DOM加载完成之前都不会被执行.
2. 动态脚本元素: 返回的代码通常会立即执行, 在代码包含其他接口调用时会带来问题(可以跟踪<script>节点的onload或readystatechange事件).
----- 文件在元素被添加到页面时开始下载; 无论在何时启动下载和执行过程不会阻塞页面其他进程, 推荐 append 到 head 下面.
1 var script = document.createElement("script"); 2 script.type = "text/javascript"; 3 script.src = "file1.js"; 4 document.getElementByTagName("head")[0].appendChild(script);
3. 使用XMLHttpRequest
----- 代码是在<script> 标签之外返回的(xhr的open), 下载之后不会立即执行. 浏览器兼容性好. 但是必须要求js文件与页面处于同一个域中.
4. 使用第三方库
----- LazyLoad: loadScript()的增强版本
1 <script type="text/javascript" src="lazyload-min.js"></script> 2 <script type="text/javascript"> 3 LazyLoad.js(['first-file.js','second-file.js'],function(){ 4 Application.init(); 5 }); 6 </script>
----- LABjs : 提供对加载过程的更精细的控制, 并试图下载尽可能多的代码
1 <script type="text/javascript" src="lab.js"></script> 2 <script type="text/javascript"> 3 $LAB.script("first-file.js").wait() //wait在这里保证按序执行 4 .script('the-rest-files.js') 5 .wait(function(){ // 下载完成后执行的函数 6 Application.init(); 7 }); 8 </script>