现在的位置: 首页 > easyui > Base > easyloader > 正文
jQuery Easyui Easyloader使用注意点总结
2013年02月13日 easyloader ⁄ 共 5611字 暂无评论 ⁄ 被围观 19,925 views+
文章目录
[隐藏]

首先作为新年后的第一篇技术类文章,开场白得向大家拜个晚年,祝大家在蛇年里各方面技术能有更长远的进步和积累,好了,不水了,进入正题。

同步和异步

要理解Easyloader就必须对阻塞和非阻塞加载(对应同步和异步加载)有个大体的认识,所以这两个概念,必须钉在脑子里。

同步(阻塞)加载

我们平时最常使用是将"script"或者"style"标签直接写在html文档中的方式就是典型的同步加载方式。同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止了后续的解析,因此停止了后续的文件加载(如图像)、渲染、代码执行。

javascript之所以要同步执行,是因为脚本中可能有输出document内容、修改dom、重定向等行为,所以默认同步执行才是安全的。以前的一般建议是把"script"放在页面末尾"body"之前,这样尽可能减少这种阻塞行为,而先让页面展示出来。

异步(非阻塞)加载
 
  1. function loadJs(url, callback) {   
  2.     var done = false;   
  3.     var script = document.createElement('script');   
  4.     script.type = 'text/javascript';   
  5.     script.language = 'javascript';   
  6.     script.src = url;   
  7.     //onreadystatechange和script.readyState属性事件是IE特有的,IE不支持script.onload   
  8.     //firefox,chrome等其它浏览器支持只script.onload事件   
  9.     script.onload = script.onreadystatechange = function() {   
  10.         if(!done && (!script.readyState || script.readyState == 'loaded' || script.readyState == 'complete')) {   
  11.             done = true;   
  12.             script.onload = script.onreadystatechange = null;   
  13.             if(callback) {   
  14.                 callback.call(script);   
  15.             }   
  16.         }   
  17.     }   
  18.     document.getElementsByTagName("head")[0].appendChild(script);   
  19. }  

以上方式就是实现javascript异步加载的典型代码,用js创建一个script元素并插入到document中,这样就做到了非阻塞的下载js代码。此方法被称为"Script DOM Element"法,不要求js同源。Easyui的Easyloader便是用的这种方式实现异步加载的。

需要注意两点:

  • 这种加载方式在加载执行完之前会阻止"onload"事件的触发,所以从某种意义上讲,这种方式实现的异步并不是完全的非阻塞;
  • 异步加载并不一定能减少整个页面完全加载完所需的时间,有的时候按照模块加载恰恰是进行了多次http请求导致加载变慢,这就跟拷贝一个1G的大文件速度明显优于拷贝500个1M大小文件的道理是一样的。

Easyui的加载器

加载器的使用场景
  • 你觉得一次性导入easyui的核心min Js和css太大,影响页面的相应速度,想先展示基础的文档结构给用户
  • 你只用到easyui的其中几个组件,实在没必要导入所有组件的js和css文件
  • 你想使用其中的一个组件,但是你又不知道这个组件依赖了那些组件
  • 你甚至想把jQuery这样的基础库和自己写的js库,以提高基础文档结构展示给用户的速度
加载器的属性与事件

EasyLoader的API文档请参见:jQuery Easyui EasyLoader(加载器) API文档

加载器的使用方式

Easyui的加载器的使用方式有两种:

加载模块方式
 
  1. //注意jquery,panelExtend,layoutExtend三个模块是我自定义的modul   
  2. //因为jquery也是异步加载的,jquery的相关用法必须写在回调函数里。   
  3. using(['jquery', 'parser', 'layout', 'menu', 'tabs', 'linkbutton', 'accordion', 'tree', 'panelExtend', 'layoutExtend'], function() {   
  4.     alert('全部模块异步加载完成');   
  5.     $(function(){   
  6.         alert('全部文档装载完成');   
  7.     });   
  8. });  
加载单个文件方式
 
  1. //加载单个文件方式,必须写绝对的url   
  2. using("http://wwww.easyui.info/easyui/js/index2.js"function() {   
  3.     alert('异步加载文件完成');   
  4. });  
如何自定义模块

Easyui的作为认为一个模块应该至少包含一个js文件,至于css文件并不是必要的,所以我们定义模块的时候,不能仅仅将某个css文件定义为某个模块。

同时,对于模块扩展的写法也是很有考究的,很多同学想当然用下面的写法来扩展模块:

 
  1. easyloader.modules = $.extand({},{   
  2.     "mymodule1":{   
  3.         js:'http://www.easyui.info/mymodule1.js',   
  4. css:'http://www.easyui.info/mymodule1.css'},   
  5.         "mymodule2":{   
  6.         js:'http://www.easyui.info/mymodule2.js'        css:'http://www.easyui.info/mymodule2.css'  },   
  7.         "mymodule3":{   
  8.         js:'http://www.easyui.info/mymodule3.js'        css:'http://www.easyui.info/mymodule3.css'  },   
  9.         .......   
  10. },easyloader.modules);  

这样做遇到的第一个问题是,如果jquery库也是使用异步加载的话,那么$.extend函数是不能被使用的,当然了,这个还是比较容易理解的,而且大多数童鞋的jquery库是用同步加载的,并非异步,所以不用担心这个问题。

然而第二个问题你就不得不面对了,因为这样扩展模块,加载器根本识别不了你增加的模块,为什么呢?我们来看看加载器的源码:

 
  1. (function(){   
  2.     /**
  3.         *定义一个对象modules,加载模块的时候,用的就是这个modules作为所有模块集合的  
  4.         *modules究竟是什么,它只不过是一个引用罢了,对某段堆内存的引用,真正的对象是存储在堆内存中的  
  5.         *如果在定义modules之后写有以下代码:  
  6.         *var modulesCopy = modules;  
  7.         *modulesCopy = new Object();  
  8.         *modulesCopy.draggable.js = "唐老鸭";  
  9.         *大家应该能能反应过来,modulesCopy.draggable.js重新设置值并不会影响到modules.draggable.js的值  
  10.  
  11.         *而jquery的easyloader.modules = $.extend({},modulesCopy,easyloader.modules);也是将easyloader.modules指向了另一段内存堆  
  12.         *执行过这句代码后easyloader.modules和modules已经指向两个不同内存堆  
  13.  
  14.         *那么正确的应该如何写呢?  
  15.         *easyloader.modules = $.extend(easyloader.modules,modulesCopy);这样写可以确保easyloader.modules和modules引用同一内存堆  
  16.     **/    
  17.     var modules = {   
  18.         draggable:{   
  19.             js:'jquery.draggable.js'   
  20.         }   
  21.         //此处省略诺干   
  22.     };   
  23.        
  24.     var locales = {   
  25.         'af':'easyui-lang-af.js'   
  26.         //此处省略诺干   
  27.     };   
  28.        
  29.     var queues = {};   
  30.     /**
  31.         此处省略诺干干干  
  32.     **/  
  33.     //是不是很蛋疼,用了一个没加var申明的easyloader,于是他就是全局变量了……   
  34.     easyloader = {   
  35.         modules:modules,//easyloader.modules跟modules指向同一堆内存   
  36.         locales:locales,   
  37.         base:'.',   
  38.         theme:'default',   
  39.         css:true,   
  40.         locale:null,   
  41.         timeout:2000,   
  42.         load: function(name, callback){   
  43.             //省略诺干   
  44.         },   
  45.            
  46.         onProgress: function(name){},   
  47.         onLoad: function(name){}   
  48.     };   
  49.   
  50.     //省略诺干   
  51.     window.using = easyloader.load;   
  52.     //已经存在jq的话,先把parser组件加载了,继而解析整个页面   
  53.     //很多组件还未加载,怎么能解析的呢?   
  54.     //奥妙就在parser组件内部了,parser组件会自动检测页面包含的敏感easyui样式   
  55.     //进而在使用easyloader将这个组件加载了   
  56.     if (window.jQuery){   
  57.         jQuery(function(){   
  58.             easyloader.load('parser', function(){   
  59.                 jQuery.parser.parse();   
  60.             });   
  61.         });   
  62.     }   
  63. })();  

为了节省篇幅,没多大相关的代码我都省去了,注释部分我已经讲的比较清楚了,如果还不清楚的,要好好补一下javascript基础和jquery的extend函数的用法了

最终我们要想成功增加模块,必须按照以下写法才行:

 
  1. $.extand(easyloader.modules,{   
  2.     "mymodule1":{   
  3.         js:'http://www.easyui.info/mymodule1.js',   
  4. css:'http://www.easyui.info/mymodule1.css'},   
  5.         "mymodule2":{   
  6.         js:'http://www.easyui.info/mymodule2.js'        css:'http://www.easyui.info/mymodule2.css'  },   
  7.         "mymodule3":{   
  8.         js:'http://www.easyui.info/mymodule3.js'        css:'http://www.easyui.info/mymodule3.css'  }   
  9. });   
推荐使用加载模块数组的方式

如果我们使用加载单个文件或者模块的方式,势必会牵扯到一个问题,如果文件或者模块间有依赖关系,我们就必须在回调函数里加载高级模块,如此一来回调函数可能就要嵌套很多层了。

而是用加载模块数组的方式,EasyLoder的内部实现了按照数组元素先后顺序同步加载,即,只要基础库写在数组前面就可以确保被同步优先加载。

对于Easyui自带组件之间的依赖,EasyLoder也有自身的算法,确保Easyui的基础类组件会被同步优先加载。如此一来,至少在代码的可读和可维护性上讲,优雅了很多。

最后的总结

异步加载的水还是比较深的,个人觉得easyui的核心文件也不是很大,没有特殊需求的同学就不要使用异步方式了,别把自己搞得焦头烂额,如果实在要使用而又没经验的,请细读本文,我想不会让你失望的。

要异步加载的演示?其实我的那个依旧待完善的API在线文档就是演示,它演示了异步方式如果是比同步方式更加的慢,典型的反面教材:

http://www.easyui.info/easyui

给我留言

留言无头像?


×