QWrap入门之apps种子应用

开发 前端
就像是一棵树有很多果实一样,QWrap也有很多apps,本文讲解种子应用。“种子”是沿用YUI3的说法,种子应用是解决模块加载问题的应用,包括:模块预加载、异步按需加载、模块应用。

就像是一棵树有很多果实一样,QWrap也有很多apps,本文讲解种子应用。“种子”是沿用YUI3的说法,种子应用是解决模块加载问题的应用,包括:模块预加载、异步按需加载、模块应用。

apps果实篇之:种子

或许有些同学对异步加载模块不大熟悉,没关系,我们先感性的看一下这段代码

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">  
  2. <html>  
  3. <head>  
  4. <title>QW应用之一:seed_youa</title>  
  5. <meta http-equiv="Content-Type" content="text/html; charset=GB2312" />  
  6. <script type="text/javascript" src="http://dev.qwrap.com/resource/js/apps/seed_youa.combo.js"></script>  
  7. </head>  
  8. <body>  
  9. <div id="div1">div1-----<span class="content">时间</span></div>  
  10. <div id="div2">div2-----<span class="content">时间</span></div>  
  11. <input type=button value="点击后按需加载后并修改div1/div2" onclick="test()"/>  
  12. <script type="text/javascript">  
  13. function test(){  
  14.     QW.use('jQuery,YouaCore',function(){  
  15.         $('#div1').css('color','red').find('>.content').html(new Date()+'');//这段代码用到了jquery用法  
  16.         W('#div2').css('color','blue').query('.content').html(new Date().format('YYYY-MM-dd hh:mm:ss'));//这段代码用到了Youa版的QWrap  
  17.     });  
  18. }  
  19. </script>  
  20. </body> 

 

1. 如果用户浏览此网页时,只加载了一个体积很小的seed_youa.combo.js这个js(其实就是seed_youa.js(http://dev.qwrap.com/resource/js/apps/seed_youa.js)),这个js经yui压缩后的大小为4K。

2. 当用户点击按钮时,按钮对应的js用到jQuery与YouaCore,点击后才会去加载那两个jQuery与YouaCore对应的js,之后才有运行效果。

3. 第二次点击按钮,由于前面已经加载过js,所以这次会直接运行按钮事件。

分析一下以上三步,分两种情况。

A. 对于只进行了第一步操作的用户,他们用seed_youa.js替代了jQuery与YouaCore两个js的流量(这是好处甲);

B. 对于进行过第二步操作的用户,由于以上流量的节约,会让用户提前能够点击按钮(这是好处乙),点击后异步加载需要的js,加载完后事件才运行,即点击与运行存在一个时间差(这是坏处甲),并且三个js都用到了,相对于传统写法,http多了一个seed_youa.combo.js(这是坏处乙)。

另外,对于页面程序员来说,他在写按钮事件时,只需要知道自己的这段js用到了哪些模块,而不用关心这些模块是否已经加载(这是好处丙),不过,他引用模块的方式有了一些变化(少键入html代码,多键入js代码)。

好处甲、好处乙、好处丙、坏处甲、坏处乙,还有些没有分析到的好处与坏处,反正有利有弊。

那么,在什么情况下利大于弊、什么情况下弊大于利,而我们该如何兴利除弊?

如果这个页面的用户100%不会点击按钮,则几乎没坏处,只有好处甲、好处丙。

如果页面100%的用户会点击按钮,则需要权衡再权衡利弊再想办法。

好的,我们先暂且搁置这些细节,因为以上内容已足够让同学们对“异步按需加载”有了感性的认识。我们把提供这种异步按需加载的js叫种子(seed)。

我们看一下seed_youa.js,它是一个组合js(即前面一篇文章所说的B类apps:开发时可以是多个文件,但上线时会先合并后上线。)

它由三个js组成:

  1. document.write('<script type="text/javascript" src="' + srcPath + 'core/core_base.js"><\/script>');  
  2. document.write('<script type="text/javascript" src="' + srcPath + 'core/module.h.js"><\/script>');  
  3. document.write('<script type="text/javascript" src="' + srcPath + 'apps/youa_modules_config.js"><\/script>') 

core/core_base.js是QWrap的主干js
core/module.h.js是模块管理器,也是一个Helper,提供三个方法:addConfig、use、provide,代码参见:http://dev.qwrap.com/resource/js/core/module.h.js
youa_modules_config.js是youa项目只所使用到的常用模块配置,通过addConfig进行模块配置,代码如下:

  1. /*Lib Module*/ 
  2. QW.ModuleH.addConfig({  
  3.     YouaCore: {  
  4.         url: '//apps/core_dom_youa_lazy.combo.js',  
  5.         loadedChecker:function(){  
  6.             return !!(QW.W);  
  7.         }  
  8.     },  
  9.     Ajax: {  
  10.         url: '//components/ajax/ajax.youa.js',  
  11.         requires: 'YouaCore' 
  12.     },  
  13.     Anim: {  
  14.         url: '//components/animation/anim.js',  
  15.         requires: 'YouaCore' 
  16.     },  
  17.     Cookie: {  
  18.         url: '//components/cache/cache.js',  
  19.         requires: 'YouaCore' 
  20.     },  
  21.     Storage: {  
  22.         url: '//components/cache/cache.js',  
  23.         requires: 'YouaCore' 
  24.     },  
  25.     Drag: {  
  26.         url: '//components/drag/drag.js',  
  27.         requires: 'YouaCore' 
  28.     },  
  29.     Editor: {  
  30.         url: '//components/editor/editor.js',  
  31.         requires: 'YouaCore,Panel' 
  32.     },  
  33.     Panel: {  
  34.         url: '//components/panel/panel.js',  
  35.         requires: 'YouaCore' 
  36.     },  
  37.     Suggest: {  
  38.         url: '//components/suggest/suggest.js',  
  39.         requires: 'YouaCore' 
  40.     },  
  41.     "Switch": {  
  42.         url: '//components/switch/switch.js',  
  43.         requires: 'YouaCore' 
  44.     },  
  45.     Tree: {  
  46.         url: '//components/tree/tree.js',  
  47.         requires: 'YouaCore' 
  48.     },  
  49.     Valid: {  
  50.         url: '//components/valid/valid.js',  
  51.         requires: 'YouaCore' 
  52.     },  
  53.     jQuery: {  
  54.         url: 'http://common.cnblogs.com/script/jquery.js',  
  55.         loadedChecker:function(){  
  56.             return !!(window.jQuery && window.jQuery.fn);  
  57.         }  
  58.     }  
  59. });   
  60.  
  61. /*Logic Module*/ 
  62. QW.ModuleH.addConfig({  
  63.     "User": {  
  64.         url: '//global/userv3.js',  
  65.         requires: 'YouaCore',  
  66.         loadedChecker: function() {  
  67.             return !!window.topbar;  
  68.         }  
  69.     },  
  70.     ShopMap: {  
  71.         url: '//sp/map/shopmap.js',  
  72.         requires: 'YouaCore' 
  73.     }  
  74. }); 

看到这个配置文件的同学也许会问:模块添加得越来越多会怎么办?为什么不像YUI一样,在各个模块的js里进行addConfig,而要集中起来addConfig?

不错,理论上是会越来越大,但是,实际上最大能大到多少?并且不一定是所有的模块配置都要放在这里面。在页面的js里也可以QW.addConfig('MyPageJs','//my.js')的。所谓的太大,只是个理论问题,不是个实际问题。

YUI在各个模块的js里进行add,有好处,也有坏处。

好处就是多了个沙箱机制,沙箱理论看起来很严谨,可以满足YUI的严谨性洁癖----其实我一直没有理解它对实用者都有啥好处。

而坏处,也有很多。例如:

1.  需要模块的代码来适应他的加载机制。----例如,jQuery也可以算是个模块,凭什么要让独立的jquery来改代码?

2.  假设我改了jQuery的代码来适应这loader,那是不是也损失了jQuery的原来的用法,即预加载模式用法(在HTML的Header里引用jquery.js,在页面直接用$('#id').show())。

3.  例如use('Editor',function(){})时,其实由于依赖关系,会按需加载YouaCore,Drag,Panel,Editor四个js,因为依赖关系是在各自的js里,理论上无法将四个请求合并成一个请求,也无法在请求editor.js时就并行请求drag.js。

4.  如果客户端缓存了js,我们更新Editor.js后,use('Editor',function(){})无法知道是否需要在editor.js后添加版本号。

5.  如果有复合模块,例如core_dom_youa_lazy.js其实是同时拥有很多小模块功能的一个js,那在drap.js里如何定义依赖?

而QWrap的“集中配置”方式,上面几条都不是什么问题。

对于第一条第二条,已经解决,即:addConfig时的loadedChecker参数。

例如,这样配置jQuery:

  1. QW.ModuleH.addConfig({  
  2.     jQuery: {  
  3.         url: 'http://common.cnblogs.com/script/jquery.js',  
  4.         loadedChecker:function(){  
  5.             return !!(window.jQuery && window.jQuery.fn);  
  6.         }  
  7.     }  
  8. });  

这个jQuery引用的是博客园网站的,我们没有作任何修改。

如果页面已经预加载了jquery,运行QW.use('jQuery',function(){})也不会再次加载jquery.js。

当然,用户还可以保持习惯,用以前的预加载经典用法。

对于第三条合并请求与并行请求,QW目前还没做,不过,只需调整一下module.h.js里的某一段代码即可。在源代码里有说明:

  1. function loadsJsInOrder() {  
  2.       //浏览器不能保证动态添加的ScriptElement会按顺序执行,所以人为来保证一下  
  3.       //参见:http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/  
  4.       //测试帮助:http://1.cuzillion.com/bin/resource.cgi?type=js&sleep=3&jsdelay=0&n=1&t=1294649352  
  5.       //todo: 目前没有充分利用部分浏览器的并行下载功能,可以改进。  
  6.       //todo: 如果服务器端能combo,则可修改以下内容以适应。  
  7.       var moduleI = loadingModules[0];  
  8.       function loadedDone() {  
  9.           moduleI.loadStatus = 2;  
  10.           var cbs = moduleI.__callbacks;  
  11.           for (var i = 0; i < cbs.length; i++) {  
  12.               cbs[i]();  
  13.           }  
  14.           isLoading = false;  
  15.           loadsJsInOrder();  
  16.       }  
  17.       if (!isLoading && moduleI) {  
  18.           //alert(moduleI.url);  
  19.           isLoading = true;  
  20.           loadingModules.splice(0, 1);  
  21.           var checker = moduleI.loadedChecker;  
  22.           if (checker && checker()) { //如果有loaderChecker,则用loaderChecker判断一下是否已经加载过  
  23.               loadedDone();  
  24.           } else {  
  25.               loadJs(moduleI.url.replace(/^\/\//, QW.PATH), loadedDone);  
  26.           }  
  27.       }  
  28.   } 

对于第四条缓存,由于是统一配置,所以只需在发布时,在配置文件的js后面加上对应js的md5码的前N位即可。

例如,线上的配置可能是:

  1. Ajax: {  
  2.       url: '//components/ajax/ajax.youa.js?111111.js',  
  3.       requires: 'YouaCore' 
  4.   },  
  5.   Anim: {  
  6.       url: '//components/animation/anim.js?222222.js',  
  7.       requires: 'YouaCore' 
  8.   } 

页面引用的种子,也是在后面加上它的md5码的前N位。

这样做的好处是:每次上线后,用户也只需下载有过修改的js。

对于第五条的复合模块问题,由于是统一配置,所以根本就不是问题。

说了seed_youa.js的这么多好处,当然还要说明一个限制:项目中需要有一个水平还过得去的js同学,来负责这个统一的模块配置文件。

关于module.h.js还有挺多内容要讲的,不过,绝大同学不用关心它的实现;关心他的实现的同学大多也看过NK行的YUI3种子,再看这个两百行的module.h.js,应该是小case,这里先略过。

小结一下,QWrap的这个种子应用是绿色版的,并且小巧、灵活,可以直接复制过去引用。不过需要注意一下你所放的路径,防止QW.PATH的值计算有误,或者强制改掉QW.PATH的值。

附:QWrap网址:http://www.qwrap.com

原文:http://www.cnblogs.com/jkisjk/archive/2011/04/15/qwrap_apps_seed_youa.html

【编辑推荐】

  1. 云端JavaScript漫游指南(视频)
  2. QWrap选择器的一个bug:tagName的大小写
  3. jQuery是如何工作的
  4. 7个优秀的JavaScript资源推荐
  5. 浅析淘宝数据魔方技术架构
责任编辑:陈贻新 来源: JKisJK的博客
相关推荐

2011-08-09 15:59:51

QWrap

2011-08-10 15:41:20

QWrap

2011-11-29 16:38:58

Knockout

2010-05-04 09:42:14

云计算

2011-07-22 17:05:13

Samsung App三星应用商店

2024-01-03 15:31:16

网格布局ArkTSGrid

2014-07-07 17:16:18

2013-04-03 10:00:11

2015-12-18 10:20:41

微软谷歌Android

2012-02-28 15:39:48

2009-04-12 09:25:12

Symbian诺基亚移动OS

2011-09-27 13:16:15

iptables

2012-04-16 14:51:26

软件广联达

2013-04-19 09:46:05

移动应用开发解决方案mobile apps

2012-02-29 00:49:06

Linux学习

2013-01-25 15:13:58

Series 40S40

2009-05-04 13:32:28

Google AppsLDAPDirectory S

2011-08-08 13:15:35

QWrap

2022-11-04 14:58:59

应用开发鸿蒙

2009-06-10 15:14:00

点赞
收藏

51CTO技术栈公众号