首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

kissyLite的保管理和无需预先注册的带依赖关系模块异步加载

2012-11-06 
kissyLite的包管理和无需预先注册的带依赖关系模块异步加载现在很多同学们都在代码里模拟YUI3实现JavaScri

kissyLite的包管理和无需预先注册的带依赖关系模块异步加载
现在很多同学们都在代码里模拟YUI3实现JavaScript异步模块化加载,也就是一个add,一个use..
YUI3里对模块的加载是串行模式,当没有combo配合时,看起来很不美观.
今天army8735同学提到这个事儿,发现还真是很多同学注意到了这一点.kissy本身的add use就是并行,也有同学对YUI3做了改进.

而进来我正在开发kissylite,是kissy的一个支持有限方法的子集,目标是用1.5k代码支持包管理和模块化管理,也遇到了这个问题.不如拿出来一起讨论.

我觉得kissy和yui3的问题是模块必须先注册,这样扩展性有一定的局限.
kissylite引入了包的概念,每一个包对应一个codebase,通过模块名就完全确定js所在路径.
那么在一个包内新增了模块之后,种子文件是不需要修改即可直接使用的.

这样增加循环依赖的风险a->b b->c c->a..
虽然这样循环了明显是程序逻辑错误,但是如果不加以防范,合作开发,多次上线,死循环漏到线上那打击是致命的..
我的解决办法很土..在env中有一个对象记录x=模块依赖哪些,又支持哪些..当出现x依赖x的时候就抛一个error出来好了.

以a->b b->c c->a为例use("a")时:
首先载入a,Env中:
依赖关系方面a->b,
支持关系方面b->a

然后载入b,Env中:
依赖关系方面:b->c,在通过上面的支持关系可以得到a同样依赖c,即a->b,c
支持关系方面:c->b;a,b->a

最后载入c,Env中:
依赖关系方面:c->a,再通过现有的支持关系能得到a->b,c,a 矛盾出现a依赖自己,报个错吧:循环依赖.

这种算法效率是很低的,但是先粗暴的实现一下用着,每次add可能都要访问相关依赖关系对象和支持关系对象,毕竟kissylite目标是给页面中的广告,这类小应用的,模块不会太多.算抛砖吧,求更好的算法.

另一方面这里看到a b c的加载是串行的,在开发完成后,每次use可以自动给出一个use的并行优化方案.
比如use("a"),在use成功后,可以控制台log一下,为了更好的并行加载模块,你应该use("a,b,c")..这样就可以边开发,边优化.

kissylite还解决了一个问题,就是add的时候永远不attach.
steve blog:Evolution of Script Loading给出的mobile上js加载方案,看到代码从按需加载进化到了按需执行的阶段.
对于模块化js简单一些,只要不先attach,只是一个单纯简单的add,耗费的精力少的多了.

大家可能担心use时候attach是不是慢了些,这个同样可以边开发边优化.
在开发一个页面,可以把常用的功能都跑一边,Env中包含你所有使用过的包.
那么就可以在domready后,不忙的时候把这些先use一遍...
这就有点facebook primer的意思了,domready之前按需执行,domready之后选择性预热.

这里也说说异步执行单元的串行和并行.这个老道正好在velocity china提到.
异步执行单元:asyncUnit(args,callback).所有可能需要等待一段时间才能收到结果的函数都可以叫异步单元.比如getScript(url,callback),use(mods,callback),还有一些动画回调,都是异步执行单元.

我们常常遇到很多异步执行单元,比如use(mods)这个场景.
按程序的业务逻辑,如果这些异步单元需要串行,则会遇到多层复杂的callback嵌套.

a(a1,function(resA){    window.resA = resA    if(window.resB){       c();    }});b(b1,function(resB){    window.resB = resB    if(window.resA){      c();    }})function c(){   //your code run after resA & resB returend }

这种代码同样不美观,通过写死判断条件if(resA/B)每次手动检查其他相关异步单元执行情况.

kissylite增加了方法multiAsync(asyncers,callback),因为use时并发的情况较多,先解决并发这个问题,计划再增加一个参数,解决串行异步单元的问题..

最后附一下kissylite的readme,以及googlecode上临时预览地址:http://tbad.googlecode.com/svn/trunk/kslite/testcase/test_loader.html

kslite为kissy的仅支持有限方法的子集:
这些方法包括log,mix,clone,extend,add,use,getScript,substitute
kslite为所在页面引入KSLITE全局对象.

相比于kissy,发生变化的方法如下:
add:任何时候只add,不attach.
use:不用add即可直接use,详见下面的包和模块管理.

包和模块管理:
模块名由包名,路径,文件名.三部分构成
如{packagename}-{path_0}-...-{path_n}-{filename}
包类似*.jar,每个包对应一个codebase即classesroot.在S.config.lt_pkgs中配置
是一个http地址,如果没有则以为kslite.js所在地址为base.
比如:
    S.Config.lt_pkgs={
        inf:"http://a.alimama.cn/kslite/",
        test:"http://demo.taobao.com/tbad/kslite"
    }
模块"inf-a"对应地址 http://a.alimama.cn/kslite/inf/a.js
模块"test-t-1"对应地址 http://demo.taobao.com/tbad/kslite/test/t/1.js
这样根据模块名称即可定位模块地址,所以不需要add预先注册模块即可直接use.
add不执行attach.只有第一次use的时候才执行attach.
add同样支持require.可以在载入js后根据require串行加载更多模块.(已处理循环引用风险,办法很土.)
暂时不支持use外部JS文件,如use("jquery.js");

性能方面考虑:
这种模式只要use中包含的模块足够,满足所有依赖,则可以保证所有模块并行load,否则可能存在串行情况.
开发时使用小模块模式,每一个正式产出,比如生成广告投放用inf.js,广告展现用showad.js应该手动combo.
因为在use时会按照require顺序attach,所以手动combo的代码不需要关心模块间顺序.

其他配置项:
kslite相关配置项,在局部变量kslite_config中,之后mix入S.Config
lt_b:kslite的base,推荐每个产出写死一个kslite的base地址,而不是通过currentScript获得.因为kslite不一定作为<script>节点静态引入
lt_pkgs:包路径信息,如上.
lt_t:时间戳比如20101129.js
lt_v:版本 如1.1.5 计划沿用kissy版本.

关于与kissy兼容性:
在页面存在同一版本的Kissy实例时,S.app("KSLITE")构建.
同时根据当前kissy的add模式,需要额外生成一段代码,将所需模块预先注册一下. 1 楼 xinyu198736 2010-12-12   你写博客速度真快,羡慕.... 2 楼 limu 2010-12-12   这个早写给玉伯啦,玉伯大大最近太忙,还没review,哈哈.. 3 楼 xinyu198736 2010-12-12   limu 写道这个早写给玉伯啦,玉伯大大最近太忙,还没review,哈哈..
原来你就是李牧大大,哈哈

热点排行