使用kissyLite支持第
 三方内容开发
                 李牧
           2010-12-16
inf.js-2.0
<script>

  alimama_pid="mm_1_2_3";alimama_type=2;

  alimama_width=270;alimama_height=390;

</script>

<script src="http://a.alimama.cn/inf.js"></script>
inf.js-3.0
<script>

  alimama_pid="mm_1_2_3";alimama_type=2;

  alimama_width=270;alimama_height=390;

</script>

<script src="http://anydomain/inf.js"></script>
inf.js-3.0
<script src="http://anydomain/inf.js"></script>

<script>

  alimama_pid="mm_1_2_3";alimama_type=2;

  alimama_width=270;alimama_height=390;

   window.alimama_show && alimama_show();

</script>
inf.js-3.0
<!-- http://anydomain/any.js include the content of inf.js -->

<script src="http://anydomain/any.js"></script>

<script>

  alimama_pid="mm_1_2_3";alimama_type=2;

  alimama_width=270;alimama_height=390;

  window.alimama_show && alimama_show();

</script>
inf.js-3.0
<script>

   //content of inf.js

</script>

<script>

  alimama_pid="mm_1_2_3";alimama_type=2;

  alimama_width=270;alimama_height=390;

  window.alimama_show && alimama_show();

</script>
alimama_show()
http://a.com/a.html:             <head>
                                   <script src="main.js"></script>
                                 </head>


<script src="inf.js"></script>
<script>
  alimama_show();
</script>                        <div>
                                   <!-- ad content-->
                                 </div>

<iframe src="" style="display:none !important" id="anchor-pid">
   <!-- ad content-->destory iframe onunload onbeforeunload
</iframe>
Inf.js – 3.0 需求&功能
•   需求               •   功能

    •   必须稳定             •   "alimama_" 变量收集

    •   足够小              •   锚点/容器 iframe 输出

    •   可扩展 -- 结构化       •   动态内容无阻引入

                         •   kissyLite
kissyLite

kissylite,是kissy的一个支持有限
方法的子集
目标是用1.5k代码支持包管理和
模块化管理
                预览地址
ksLite -- 足够小
统一风格的OOP,异步的带依赖关系模块化,简单的模板.

•   S.mix

•   S.extend

•   S.clone

•   S.add

•   S.use

•   S.getScript

•   S.substitute
ksLite -- 基于包的扩展
包内无限可扩展 => 模块名由包名,路径,文件名.三部分构成.

{packagename} - [ {path_0} - ... - {path_n} - ] {filename}

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
ksLite -- 基于包的扩展
可扩展无限包 => package root router

在一个地址记录所有可用的包以及对应的class root.

S.Config.lt_pkgrouter = http://a.alimama.cn/kslite/router.js

S.mix(S.Config.lt_pkgs,{

      pkg1:"http://a.alimama.cn/pkg1/",

      pkg2:"http://demo.taobao.com/tbad/pkg2/"

});

当自带S.Config.lt_pkgs没有相关配置时询问pkgrouter.
ksLite -- 命名约定
S.add("pkg1-path1-mod1",function(S,P){

      S["pkg1"] = S["pkg1"] || {};

      P = S["pkg1"];

});

S.use("pkg1-path1-mod1",function(S,P){});

保证包内对象都在名称空间P,即S.P内.

相当于另一个途径实现S.app(),嵌入至S的app.

为了被Kissy兼容,P只能作为开发约定,手动写在每个包中.
ksLite -- 轻量的add
S.add = function(name, fn, config){

    var mods = S.Env.mods, mod;

    if (mods[name] && mods[name].status > INIT)return;

    mod = {name: name,fn: fn || null,status: LOADED};

    mods[name] = S.mix(mod,config);

}

不提前attach,保证模块在使用之前没有多余的代码执行消耗.

可选优化:domready之前按需执行,domready之后选择性预热.
kissyLite -- 简单的use
S.use = function(modNames, callback){

    var mods = S.Env.mods;

    modNames = modNames.split(',');

    S.attachMods(modNames, function(){

          if (callback) callback(S);

    });

}

将attachMods单独提出来.不止供use中使用.
ksLite – 明确的attachMod
如果模块LOADED,直接attach.

如果模块没有LOADED,则异步载入模块.然后attach.



模块load之后,attach时如果发现requires.

attachMods(requires,callbcak).之后attach.
asyncer -- 异步执行单元
/*

* @interface asyncer 可能需要等待再回调的function.

* @param { * } args

* @param { Function | Object } callback info

* @param {number} timeout(ms)

* @return {Object}

*/

function ayncer(args , callback,timeout){ }
parallel asyncers 
asyncerA(a,function(resA){
    window.resA = resA;
    if(window.resB)c();
});

asyncerB(b,function(resB){
   window.resB = resB;
   if(window.resA)c();
})

function c(){
  //your code run after resA & resB both returend.
}
serial asyncers 
asyncerA(a,function(resA){
      asyncerB(b,function(resB){
            asyncerC(c,function(resC){
                 //your code.
            })
      });
});
S.multiAsync 
S.multiAsync(asyncers,callback,timeout,isSerial);
实例:
S.attachMods = function(modNames,callback){
  var i, asyncers = {};
  for (i = 0; i < modNames.length; i++) {
     asyncers[modNames[i]] = {
         f: S.attachMod,
         a: modNames[i]
     };
  }
  S.multiAsync(asyncers, callback);
}
串行模块加载优化
场景:

  mod-a requires mod-b

  mod-b requires mod-c

开发时:

  S.use(“mod-a”,function(){}); //串行的载入mod-a,mod-b,mod-c.效率不高

代码开发完成,发布上线之前,手动预编译优化(就是Google Closure做事的时候):

  S.log("should use('mod-a,mod-b,mod-c') here for parallel download !");

  S.log("should combine 'mod/b.js','mod/c.js' to 'mod/a.js' for reduce requests !");
避免循环引用
模块和包都是无限可扩展的,一旦出现循环引用,影响客户页面稳定性

场景:

  mod-a requires mod-b

  mod-b requires mod-c

  mod-c requires mod-a

运行时:

  S.use("mod-a",function(){});

  throw new Error("Fatal Error,Loop Reqs!");
简单粗暴的算法
在env中有一个对象记录

  x模块依赖哪些模块

  x模块支持哪些模块

当出现x依赖x的时候 thorw error.
避免循环引用实例
Load mod-a => requires b

  依赖关系:

      a => b

  支持关系

      b <= a
避免循环引用实例
Load mod-b => requires c

  依赖关系:

      a => b , c

      b => c

  支持关系:

      b <= a

      c <= b , a
避免循环引用实例
Load mod-c => requires a

  依赖关系:

      a => b , c , a

      b => c , a

      c => a

  a依赖a throw Error.
简单粗暴的算法

多次遍历 + 数据冗余.
广告类小应用勉强可以.

求更好的算法
被Kissy兼容

S.app("KSLITE");



仍然是发布前预编译时,生成面向KISSY.add的模块注册代码.
End

使用kslite支持第三方内容开发